diff --git a/src/crypt.c b/src/crypt.c index d9bf8520..8753f480 100644 --- a/src/crypt.c +++ b/src/crypt.c @@ -78,6 +78,7 @@ struct crypt_ctx { int encrypt; SSH2_CIPHER_T(algo); ssh2_cipher_ctx h; + int privkeyfile; /* for chachapoly decrypt */ struct chachapoly_ctx chachapoly_ctx; }; @@ -87,13 +88,14 @@ static int crypt_init(LIBSSH2_SESSION *session, const struct crypt_method *method, unsigned char *iv, int *free_iv, unsigned char *secret, int *free_secret, - int encrypt, void **abstract) + int encrypt, int privkeyfile, void **abstract) { struct crypt_ctx *ctx = SSH2_ALLOC(session, sizeof(struct crypt_ctx)); if(!ctx) return LIBSSH2_ERROR_ALLOC; ctx->encrypt = encrypt; + ctx->privkeyfile = privkeyfile; ctx->algo = method->algo; if(ssh2_cipher_init(&ctx->h, ctx->algo, iv, secret, encrypt)) { SSH2_FREE(session, ctx); @@ -310,12 +312,12 @@ static int crypt_init_arcfour128(LIBSSH2_SESSION *session, const struct crypt_method *method, unsigned char *iv, int *free_iv, unsigned char *secret, int *free_secret, - int encrypt, void **abstract) + int encrypt, int privkeyfile, void **abstract) { int rc; rc = crypt_init(session, method, iv, free_iv, secret, free_secret, - encrypt, abstract); + encrypt, privkeyfile, abstract); if(rc == 0) { struct crypt_ctx *cctx = *(struct crypt_ctx **)abstract; unsigned char block[8]; @@ -383,7 +385,8 @@ static int crypt_init_chacha20_poly(LIBSSH2_SESSION *session, const struct crypt_method *method, unsigned char *iv, int *free_iv, unsigned char *secret, int *free_secret, - int encrypt, void **abstract) + int encrypt, int privkeyfile, + void **abstract) { struct crypt_ctx *ctx = SSH2_ALLOC(session, sizeof(struct crypt_ctx)); @@ -393,6 +396,7 @@ static int crypt_init_chacha20_poly(LIBSSH2_SESSION *session, return LIBSSH2_ERROR_ALLOC; ctx->encrypt = encrypt; + ctx->privkeyfile = privkeyfile; ctx->algo = method->algo; if(chachapoly_init(&ctx->chachapoly_ctx, secret, method->secret_len)) { @@ -430,7 +434,7 @@ static int crypt_encrypt_chacha20_poly_buffer(LIBSSH2_SESSION *session, ret = chachapoly_crypt(&ctx->chachapoly_ctx, seqno, buf, buf, buf_len - 4, 4, ctx->encrypt); } - else { + else if(!ctx->privkeyfile) { /* buf is full packet including size and auth tag but buf_len does not include size */ if(buf_len < 4) @@ -444,6 +448,10 @@ static int crypt_encrypt_chacha20_poly_buffer(LIBSSH2_SESSION *session, if(ret == 0) memmove(buf, buf + 4, buf_len - 4); } + else + /* for private key decryption */ + ret = chachapoly_crypt(&ctx->chachapoly_ctx, seqno, buf, buf, + buf_len, 0, ctx->encrypt); } return ret == 0 ? 0 : 1; /* success: 0, fail: 1 */ diff --git a/src/kex.c b/src/kex.c index 435a9757..e33233ea 100644 --- a/src/kex.c +++ b/src/kex.c @@ -237,7 +237,7 @@ static int kex_finish(LIBSSH2_SESSION *session, } if(session->local.crypt->init(session, session->local.crypt, iv, - &free_iv, secret, &free_secret, 1, + &free_iv, secret, &free_secret, 1, 0, &session->local.crypt_abstract)) { SSH2_FREE(session, iv); SSH2_FREE(session, secret); @@ -281,7 +281,7 @@ static int kex_finish(LIBSSH2_SESSION *session, "key exchange"); } if(session->remote.crypt->init(session, session->remote.crypt, iv, - &free_iv, secret, &free_secret, 0, + &free_iv, secret, &free_secret, 0, 0, &session->remote.crypt_abstract)) { SSH2_FREE(session, iv); SSH2_FREE(session, secret); diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h index 825e2088..e2f8a6e6 100644 --- a/src/libssh2_priv.h +++ b/src/libssh2_priv.h @@ -1055,7 +1055,7 @@ struct crypt_method { int (*init)(LIBSSH2_SESSION *session, const struct crypt_method *method, unsigned char *iv, int *free_iv, unsigned char *secret, int *free_secret, - int encrypt, void **abstract); + int encrypt, int privkeyfile, void **abstract); int (*get_len)(LIBSSH2_SESSION *session, unsigned int seqno, unsigned char *data, size_t data_size, unsigned int *len, void **abstract); diff --git a/src/pem.c b/src/pem.c index a07db50c..ba7f0517 100644 --- a/src/pem.c +++ b/src/pem.c @@ -297,8 +297,8 @@ int ssh2_pem_parse(LIBSSH2_SESSION *session, } /* Initialize the decryption */ - if(method->init(session, method, iv, &free_iv, secret, &free_secret, 0, - &abstract)) { + if(method->init(session, method, iv, &free_iv, secret, + &free_secret, 0, 1, &abstract)) { ssh2_explicit_zero(secret, sizeof(secret)); goto out; } @@ -579,19 +579,22 @@ static int pem_parse_data_openssh(LIBSSH2_SESSION *session, goto out; } - iv_part = SSH2_CALLOC(session, ivlen); - if(!iv_part) { - ret = ssh2_err(session, LIBSSH2_ERROR_PROTO, - "Could not alloc iv part"); - goto out; + if(ivlen) { + iv_part = SSH2_CALLOC(session, ivlen); + if(!iv_part) { + ret = ssh2_err(session, LIBSSH2_ERROR_PROTO, + "Could not alloc IV part"); + goto out; + } } memcpy(key_part, key, keylen); - memcpy(iv_part, key + keylen, ivlen); + if(iv_part) + memcpy(iv_part, key + keylen, ivlen); /* Initialize the decryption */ if(method->init(session, method, iv_part, &free_iv, key_part, - &free_secret, 0, &abstract)) { + &free_secret, 0, 1, &abstract)) { ret = LIBSSH2_ERROR_DECRYPT; goto out; } @@ -604,9 +607,16 @@ static int pem_parse_data_openssh(LIBSSH2_SESSION *session, } if(method->flags & SSH2_CRYPT_FLAG_REQUIRES_FULL_PACKET) { + if(!ssh2_check_length(&decoded, method->auth_len)) { + ret = ssh2_err(session, LIBSSH2_ERROR_PROTO, + "OpenSSH key full packet auth tag missing"); + method->dtor(session, &abstract); + goto out; + } if(method->crypt(session, 0, decrypted.data, decrypted.len, &abstract, MIDDLE_BLOCK)) { - ret = LIBSSH2_ERROR_DECRYPT; + ret = ssh2_err(session, LIBSSH2_ERROR_DECRYPT, + "OpenSSH key full packet decrypt failed"); method->dtor(session, &abstract); goto out; } @@ -622,7 +632,8 @@ static int pem_parse_data_openssh(LIBSSH2_SESSION *session, */ if(method->crypt(session, 0, decrypted.data + len_decrypted, blocksize, &abstract, MIDDLE_BLOCK)) { - ret = LIBSSH2_ERROR_DECRYPT; + ret = ssh2_err(session, LIBSSH2_ERROR_DECRYPT, + "OpenSSH key decrypt failed"); method->dtor(session, &abstract); goto out; } diff --git a/tests/keys-generate.sh b/tests/keys-generate.sh index 04a09828..331c7c44 100755 --- a/tests/keys-generate.sh +++ b/tests/keys-generate.sh @@ -45,7 +45,7 @@ ssh-keygen -t rsa -b 4096 -N '' -m PEM -C 'id_rsa_sha2_512_sign ssh-keygen -t rsa-sha2-512 -I "${id}" -n "${pr}" -s 'openssh_server/ca_rsa' 'keys/id_rsa_sha2_512_signed.pub' ssh-keygen -t ecdsa -b 384 -N '' -m RFC4716 -C '' -f 'keys/id_ecdsa' # empty comment -ssh-keygen -t ecdsa -b 256 -N "${pw}" -m RFC4716 -C 'id_ecdsa_encrypted' -f 'keys/id_ecdsa_encrypted' -Z aes256-ctr +ssh-keygen -t ecdsa -b 256 -N "${pw}" -m RFC4716 -C 'id_ecdsa_encrypted' -f 'keys/id_ecdsa_encrypted' -Z chacha20-poly1305@openssh.com ssh-keygen -t ecdsa -b 384 -N '' -m RFC4716 -C 'id_ecdsa_signed' -f 'keys/id_ecdsa_signed' ssh-keygen -I "${id}" -n "${pr}" -s 'openssh_server/ca_ecdsa' 'keys/id_ecdsa_signed.pub' diff --git a/tests/keys/id_ecdsa_encrypted b/tests/keys/id_ecdsa_encrypted index 100077d9..1fcc4bbd 100644 --- a/tests/keys/id_ecdsa_encrypted +++ b/tests/keys/id_ecdsa_encrypted @@ -1,9 +1,10 @@ -----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCexYpKz/ -UV1UYiV/3FlloPAAAAGAAAAAEAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlz -dHAyNTYAAABBBOq2ZOQo5aWIsS6eOUHMCtQdg5qNZnIiwLGN76QgJVySA5BZ2gCjPEpnzG -kitAXeKA/CA6E9oUrTXLfk5Pt49CgAAACwG6cRJOtaOQ8R6+mruqqbU/Pu6OqX87ulBepH -TcKpai4ou1c9WOD6FPbNyPUhrcBYo6qxrYHWMUqxfYnRKJp2UmTLNKjOSU7nY7Z/szTbov -XQnAT3Fe3ygcsmOG+HYUtFJGs0vAPZj2l/oiX84hBIX41Zw5TZIHqiRdkHBXWutTNFJ3xk -UKr7MT2bFvCcq8DCFW8clUFGsuiHdH96K4MMgT0YanviNjKCY3cEsbnxb+g= +b3BlbnNzaC1rZXktdjEAAAAAHWNoYWNoYTIwLXBvbHkxMzA1QG9wZW5zc2guY29tAAAABm +JjcnlwdAAAABgAAAAQwXm70kEh9KMQqGC2nC3ImwAAABgAAAABAAAAaAAAABNlY2RzYS1z +aGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQS6NmAMYyM3OJyytjoRAAfOojCNl7JkEG +hz5dNis8QqVkfNElFMTlclxH3//pcJdh4BPu1KPq81g6zLK2M1uDRiAAAAsAULX7/Io52P +CsWJIhzX49Hv37En5dQX+zA+3wqwW9YyN9//Ss6mD7qgLEuRVUY9HijwF3S1yTgah7GBN0 +YZfkwlOPga1/lgAPZH/LNhtdUfl6PqX4mshMLApdmI9vzLkMCNyHzEqVwjBPWU3ULK3uQl +mMX2nPJwiMUAxvyqOtVj9b9ZW7CP2pNrkWW2anb36P3YqLc2vevdJdo1LtY+h8JE0ohoiC +lvbA86fzMeLFN/t9+bbvszc/a2ry57D3WQTQ== -----END OPENSSH PRIVATE KEY----- diff --git a/tests/keys/id_ecdsa_encrypted.pub b/tests/keys/id_ecdsa_encrypted.pub index 8b09605c..2f981758 100644 --- a/tests/keys/id_ecdsa_encrypted.pub +++ b/tests/keys/id_ecdsa_encrypted.pub @@ -1 +1 @@ -ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOq2ZOQo5aWIsS6eOUHMCtQdg5qNZnIiwLGN76QgJVySA5BZ2gCjPEpnzGkitAXeKA/CA6E9oUrTXLfk5Pt49Cg= id_ecdsa_encrypted +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLo2YAxjIzc4nLK2OhEAB86iMI2XsmQQaHPl02KzxCpWR80SUUxOVyXEff/+lwl2HgE+7Uo+rzWDrMsrYzW4NGI= id_ecdsa_encrypted diff --git a/tests/openssh_server/authorized_keys b/tests/openssh_server/authorized_keys index ce94a9d8..2e940706 100644 --- a/tests/openssh_server/authorized_keys +++ b/tests/openssh_server/authorized_keys @@ -4,6 +4,6 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC92YlGoc4PJy6DzX916JJZhxkvmkWBLGJdWOL7R9B6 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDTe1lN2L/yet0Ma1JzXkQf3t1f+pauALec2FsGZy87KRJW1AOxcTTiePjlFwP1yfSK1lWXQ+uf0b61gkKqqR52FDky24HJWuYlfXlEQMn2d/PNDNVDDbO4TXKyNxxUHFJ6qYMNd4kWjOH+6rmYoWKsWV+3mDRbHagbVPEYL8wep8OTqKOqruVLVPzZyYZkBtn4XOFi6UE8WKiSVdK1Am1O5UxvlD95t32eYch6wQ9azgMqja6spe/L5UJgP83QZFknVC3wPZWkjqomVFql0FpaQclENwyY/OZMxr0cT/f7bCL6s4A/1XpbsGmC0xak4/THHbOn+0LdIej2nGV8JFoR ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDD+1l4u2KtpvsP2EpioqgHjfirT7IIQOQfCsjZCppmLUcPE1/qCC7krqjzaQ3nuKlVEc/pKJrti2oc0tBDp6zzr8pPkmzdMtpjP84RkJZwu6eVZyZqQrjpmwjw7IWVbGoxkKFpWS2ndxCzhoD/F+TW2NcjpwFN53Ktq0SdHVUXU00RlzUiKNTdzanb8vyF3m+PGwIWPX92E2t/31WxRVXwybTdpXSzyz9IIjxMkrSRVa8XzX0EyUzETuiAeU94AWJX5Gu/pFJT6E7VEMQudeN4iI75WYGxrYU1HCOTnsYk/9LCdM7O6ntJIlzul3CwXsD6+B35hu5AJb91RNbHYWUz key_rsa_aes256gcm ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBOiyJJwf+hFJrOkik9IQVxjhhVnI1vKl4BGLj03erLvw4TXXwoZzlPx6J936fU9JvvPw+d8PA4viMEfFbmdbHREKhwi3u1vZrfj0mB8SXw96AcZwX8PAL556wgom+/Qx+Q== -ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOq2ZOQo5aWIsS6eOUHMCtQdg5qNZnIiwLGN76QgJVySA5BZ2gCjPEpnzGkitAXeKA/CA6E9oUrTXLfk5Pt49Cg= id_ecdsa_encrypted +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLo2YAxjIzc4nLK2OhEAB86iMI2XsmQQaHPl02KzxCpWR80SUUxOVyXEff/+lwl2HgE+7Uo+rzWDrMsrYzW4NGI= id_ecdsa_encrypted ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFEg0II3zbc1yWGhRzIc5KwTRlmx10RQP0sS63+1oMPi ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICHxEyUTOVHXvdMFARedFQ+H9DW/n8Zy3daKKRqnTDMq