From: Nikos Mavrogiannopoulos Date: Wed, 9 May 2012 16:02:12 +0000 (+0200) Subject: Use the PKCS #1 1.5 encoding provided by nettle (2.5) for encryption and signatures. X-Git-Tag: gnutls_3_0_21~125 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6f9bfaac9d50c2fee5e4146ca9315f0769dd43c4;p=thirdparty%2Fgnutls.git Use the PKCS #1 1.5 encoding provided by nettle (2.5) for encryption and signatures. --- diff --git a/NEWS b/NEWS index 4afa452712..81e46e01ae 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,9 @@ See the end for copying conditions. * Version 3.1.0 (unreleased) +** libgnutls: Use the PKCS #1 1.5 encoding provided by nettle (2.5) +for encryption and signatures. + ** libgnutls: When decoding a PKCS #11 URL the pin-source field is assumed to be a file that stores the pin. Based on patch by David Smith. @@ -39,7 +42,7 @@ with openssl. in pkcs12 decoding tests. ** API and ABI modifications: -No changes since last version. +gnutls_pubkey_verify_hash2: Added * Version 3.0.18 (released 2012-04-02) diff --git a/doc/cha-cert-auth2.texi b/doc/cha-cert-auth2.texi index 9ebb74a0af..0c731a3753 100644 --- a/doc/cha-cert-auth2.texi +++ b/doc/cha-cert-auth2.texi @@ -616,7 +616,7 @@ The abstract key types can be used to access signing and signature verification operations with the underlying keys. @showfuncdesc{gnutls_pubkey_verify_data2} -@showfuncdesc{gnutls_pubkey_verify_hash} +@showfuncdesc{gnutls_pubkey_verify_hash2} @showfuncdesc{gnutls_pubkey_encrypt_data} @showfuncdesc{gnutls_privkey_sign_data} diff --git a/lib/abstract_int.h b/lib/abstract_int.h index ca2be2b853..ad859e55d6 100644 --- a/lib/abstract_int.h +++ b/lib/abstract_int.h @@ -36,10 +36,12 @@ int _gnutls_pubkey_get_mpis (gnutls_pubkey_t key, gnutls_pk_params_st * params); -int pubkey_verify_hashed_data (gnutls_pk_algorithm_t pk, - const gnutls_datum_t * hash, - const gnutls_datum_t * signature, - gnutls_pk_params_st * issuer_params); +int +pubkey_verify_hashed_data (gnutls_pk_algorithm_t pk, + gnutls_digest_algorithm_t algo, + const gnutls_datum_t * hash, + const gnutls_datum_t * signature, + gnutls_pk_params_st * issuer_params); int pubkey_verify_data (gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t algo, diff --git a/lib/algorithms.h b/lib/algorithms.h index e2600c605a..9fe0272541 100644 --- a/lib/algorithms.h +++ b/lib/algorithms.h @@ -106,8 +106,6 @@ enum encipher_type _gnutls_kx_encipher_type (gnutls_kx_algorithm_t algorithm); /* Functions for sign algorithms. */ gnutls_sign_algorithm_t _gnutls_x509_oid2sign_algorithm (const char *oid); -gnutls_sign_algorithm_t _gnutls_x509_pk_to_sign (gnutls_pk_algorithm_t pk, - gnutls_digest_algorithm_t mac); gnutls_pk_algorithm_t _gnutls_x509_sign_to_pk (gnutls_sign_algorithm_t sign); const char *_gnutls_x509_sign_to_oid (gnutls_pk_algorithm_t, gnutls_digest_algorithm_t mac); diff --git a/lib/algorithms/sign.c b/lib/algorithms/sign.c index ab81b830d3..b422c4c5c0 100644 --- a/lib/algorithms/sign.c +++ b/lib/algorithms/sign.c @@ -134,12 +134,12 @@ static gnutls_sign_algorithm_t supported_sign[MAX_ALGOS] = {0}; /** * gnutls_sign_get_id: - * @name: is a MAC algorithm name + * @name: is a sign algorithm name * * The names are compared in a case insensitive way. * * Returns: return a #gnutls_sign_algorithm_t value corresponding to - * the specified cipher, or %GNUTLS_SIGN_UNKNOWN on error. + * the specified algorithm, or %GNUTLS_SIGN_UNKNOWN on error. **/ gnutls_sign_algorithm_t gnutls_sign_get_id (const char *name) @@ -178,12 +178,22 @@ _gnutls_x509_oid2sign_algorithm (const char *oid) return ret; } +/** + * gnutls_pk_to_sign: + * @pk: is a public key algorithm + * @hash: a hash algorithm + * + * This function maps public key and hash algorithms combinations + * to signature algorithms. + * + * Returns: return a #gnutls_sign_algorithm_t value, or %GNUTLS_SIGN_UNKNOWN on error. + **/ gnutls_sign_algorithm_t -_gnutls_x509_pk_to_sign (gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t mac) +gnutls_pk_to_sign (gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t hash) { gnutls_sign_algorithm_t ret = 0; - GNUTLS_SIGN_LOOP (if (pk == p->pk && mac == p->mac) + GNUTLS_SIGN_LOOP (if (pk == p->pk && hash == p->mac) { ret = p->id; break;} ); @@ -200,7 +210,7 @@ _gnutls_x509_sign_to_oid (gnutls_pk_algorithm_t pk, gnutls_sign_algorithm_t sign; const char *ret = NULL; - sign = _gnutls_x509_pk_to_sign (pk, mac); + sign = gnutls_pk_to_sign (pk, mac); if (sign == GNUTLS_SIGN_UNKNOWN) return NULL; diff --git a/lib/auth/rsa.c b/lib/auth/rsa.c index 77a61f9814..f728503b89 100644 --- a/lib/auth/rsa.c +++ b/lib/auth/rsa.c @@ -298,8 +298,8 @@ _gnutls_gen_rsa_client_kx (gnutls_session_t session, gnutls_buffer_st* data) } ret = - _gnutls_pkcs1_rsa_encrypt (&sdata, &session->key->key, - ¶ms, 2); + _gnutls_pk_encrypt (GNUTLS_PK_RSA, &sdata, &session->key->key, + ¶ms); gnutls_pk_params_release(¶ms); diff --git a/lib/auth/rsa_export.c b/lib/auth/rsa_export.c index f93211d831..df78deaae6 100644 --- a/lib/auth/rsa_export.c +++ b/lib/auth/rsa_export.c @@ -159,7 +159,7 @@ proc_rsa_export_client_kx (gnutls_session_t session, uint8_t * data, return ret; } - ret = _gnutls_pkcs1_rsa_decrypt (&plaintext, &ciphertext, params, 2); /* btype==2 */ + ret = _gnutls_pk_decrypt (GNUTLS_PK_RSA, &plaintext, &ciphertext, params); if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE) { diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h index 1044f00ea9..58c7530c0e 100644 --- a/lib/crypto-backend.h +++ b/lib/crypto-backend.h @@ -311,8 +311,15 @@ const gnutls_datum_t * data, const gnutls_pk_params_st * priv); int (*verify) (gnutls_pk_algorithm_t, const gnutls_datum_t * data, - const gnutls_datum_t * signature, + const gnutls_datum_t * sig, const gnutls_pk_params_st * pub); + /* given a signature and the public parameters, + * suggest a hash algorithm */ + int (*hash_algorithm) (gnutls_pk_algorithm_t, + const gnutls_datum_t * sig, + gnutls_pk_params_st * issuer_params, + gnutls_digest_algorithm_t*); + /* sanity checks the public key parameters */ int (*verify_params) (gnutls_pk_algorithm_t, const gnutls_pk_params_st * pub); int (*generate) (gnutls_pk_algorithm_t, unsigned int nbits, diff --git a/lib/ext/signature.c b/lib/ext/signature.c index 4fe9795d8e..47724da4e8 100644 --- a/lib/ext/signature.c +++ b/lib/ext/signature.c @@ -27,6 +27,7 @@ #include "gnutls_int.h" #include "gnutls_errors.h" #include "gnutls_num.h" +#include #include #include #include @@ -264,7 +265,7 @@ _gnutls_session_get_sign_algo (gnutls_session_t session, gnutls_pcert_st* cert) || priv->sign_algorithms_size == 0) /* none set, allow SHA-1 only */ { - return _gnutls_x509_pk_to_sign (cert_algo, GNUTLS_DIG_SHA1); + return gnutls_pk_to_sign (cert_algo, GNUTLS_DIG_SHA1); } for (i = 0; i < priv->sign_algorithms_size; i++) diff --git a/lib/gnutls_pk.c b/lib/gnutls_pk.c index 738f1accf2..8c3b9d3eae 100644 --- a/lib/gnutls_pk.c +++ b/lib/gnutls_pk.c @@ -36,318 +36,6 @@ #include #include -/* Do PKCS-1 RSA encryption. - * params is modulus, public exp. - */ -int -_gnutls_pkcs1_rsa_encrypt (gnutls_datum_t * ciphertext, - const gnutls_datum_t * plaintext, - gnutls_pk_params_st * params, - unsigned btype) -{ - unsigned int i, pad; - int ret; - uint8_t *edata, *ps; - size_t k, psize; - size_t mod_bits; - gnutls_datum_t to_encrypt, encrypted; - - mod_bits = _gnutls_mpi_get_nbits (params->params[0]); - k = mod_bits / 8; - if (mod_bits % 8 != 0) - k++; - - if (plaintext->size > k - 11) - { - gnutls_assert (); - return GNUTLS_E_PK_ENCRYPTION_FAILED; - } - - edata = gnutls_malloc (k); - if (edata == NULL) - { - gnutls_assert (); - return GNUTLS_E_MEMORY_ERROR; - } - - /* EB = 00||BT||PS||00||D - * (use block type 'btype') - */ - - edata[0] = 0; - edata[1] = btype; - psize = k - 3 - plaintext->size; - - ps = &edata[2]; - switch (btype) - { - case 2: - /* using public key */ - if (params->params_nr < RSA_PUBLIC_PARAMS) - { - gnutls_assert (); - gnutls_free (edata); - return GNUTLS_E_INTERNAL_ERROR; - } - - ret = _gnutls_rnd (GNUTLS_RND_RANDOM, ps, psize); - if (ret < 0) - { - gnutls_assert (); - gnutls_free (edata); - return ret; - } - for (i = 0; i < psize; i++) - while (ps[i] == 0) - { - ret = _gnutls_rnd (GNUTLS_RND_RANDOM, &ps[i], 1); - if (ret < 0) - { - gnutls_assert (); - gnutls_free (edata); - return ret; - } - } - break; - case 1: - /* using private key */ - - if (params->params_nr < RSA_PRIVATE_PARAMS) - { - gnutls_assert (); - gnutls_free (edata); - return GNUTLS_E_INTERNAL_ERROR; - } - - for (i = 0; i < psize; i++) - ps[i] = 0xff; - break; - default: - gnutls_assert (); - gnutls_free (edata); - return GNUTLS_E_INTERNAL_ERROR; - } - - ps[psize] = 0; - memcpy (&ps[psize + 1], plaintext->data, plaintext->size); - - to_encrypt.data = edata; - to_encrypt.size = k; - - if (btype == 2) /* encrypt */ - ret = - _gnutls_pk_encrypt (GNUTLS_PK_RSA, &encrypted, &to_encrypt, params); - else /* sign */ - ret = - _gnutls_pk_sign (GNUTLS_PK_RSA, &encrypted, &to_encrypt, params); - - gnutls_free (edata); - - if (ret < 0) - { - gnutls_assert (); - return ret; - } - - psize = encrypted.size; - if (psize < k) - { - /* padding psize */ - pad = k - psize; - psize = k; - } - else if (psize == k) - { - /* pad = 0; - * no need to do anything else - */ - ciphertext->data = encrypted.data; - ciphertext->size = encrypted.size; - return 0; - } - else - { /* psize > k !!! */ - /* This is an impossible situation */ - gnutls_assert (); - _gnutls_free_datum (&encrypted); - return GNUTLS_E_INTERNAL_ERROR; - } - - ciphertext->data = gnutls_malloc (psize); - if (ciphertext->data == NULL) - { - gnutls_assert (); - ret = GNUTLS_E_MEMORY_ERROR; - goto cleanup; - } - - memcpy (&ciphertext->data[pad], encrypted.data, encrypted.size); - for (i = 0; i < pad; i++) - ciphertext->data[i] = 0; - - ciphertext->size = k; - - ret = 0; - -cleanup: - _gnutls_free_datum (&encrypted); - - return ret; -} - - -/* Do PKCS-1 RSA decryption. - * params is modulus, public exp., private key - * Can decrypt block type 1 and type 2 packets. - */ -int -_gnutls_pkcs1_rsa_decrypt (gnutls_datum_t * plaintext, - const gnutls_datum_t * ciphertext, - gnutls_pk_params_st* params, - unsigned btype) -{ - unsigned int k, i; - int ret; - size_t esize, mod_bits; - - mod_bits = _gnutls_mpi_get_nbits (params->params[0]); - k = mod_bits / 8; - if (mod_bits % 8 != 0) - k++; - - esize = ciphertext->size; - - if (esize != k) - { - gnutls_assert (); - return GNUTLS_E_PK_DECRYPTION_FAILED; - } - - /* we can use btype to see if the private key is - * available. - */ - if (btype == 2) - { - ret = - _gnutls_pk_decrypt (GNUTLS_PK_RSA, plaintext, ciphertext, params); - } - else - { - ret = - _gnutls_pk_encrypt (GNUTLS_PK_RSA, plaintext, ciphertext, params); - } - - if (ret < 0) - { - gnutls_assert (); - return ret; - } - - /* EB = 00||BT||PS||00||D - * (use block type 'btype') - * - * From now on, return GNUTLS_E_DECRYPTION_FAILED on errors, to - * avoid attacks similar to the one described by Bleichenbacher in: - * "Chosen Ciphertext Attacks against Protocols Based on RSA - * Encryption Standard PKCS #1". - */ - if (plaintext->data[0] != 0 || plaintext->data[1] != btype) - { - gnutls_assert (); - _gnutls_free_datum (plaintext); - return GNUTLS_E_DECRYPTION_FAILED; - } - - ret = GNUTLS_E_DECRYPTION_FAILED; - switch (btype) - { - case 2: - for (i = 2; i < plaintext->size; i++) - { - if (plaintext->data[i] == 0) - { - ret = 0; - break; - } - } - break; - case 1: - for (i = 2; i < plaintext->size; i++) - { - if (plaintext->data[i] == 0 && i > 2) - { - ret = 0; - break; - } - if (plaintext->data[i] != 0xff) - { - _gnutls_handshake_log ("PKCS #1 padding error"); - _gnutls_free_datum (plaintext); - /* PKCS #1 padding error. Don't use - GNUTLS_E_PKCS1_WRONG_PAD here. */ - break; - } - } - break; - default: - gnutls_assert (); - _gnutls_free_datum (plaintext); - break; - } - - if (ret < 0) - { - gnutls_assert (); - _gnutls_free_datum (plaintext); - return GNUTLS_E_DECRYPTION_FAILED; - } - - i++; - memmove (plaintext->data, &plaintext->data[i], esize - i); - plaintext->size = esize - i; - - return 0; -} - - -int -_gnutls_rsa_verify (const gnutls_datum_t * vdata, - const gnutls_datum_t * ciphertext, - gnutls_pk_params_st * params, - int btype) -{ - - gnutls_datum_t plain; - int ret; - - /* decrypt signature */ - if ((ret = - _gnutls_pkcs1_rsa_decrypt (&plain, ciphertext, params, - btype)) < 0) - { - gnutls_assert (); - return ret; - } - - if (plain.size != vdata->size) - { - gnutls_assert (); - _gnutls_free_datum (&plain); - return GNUTLS_E_PK_SIG_VERIFY_FAILED; - } - - if (memcmp (plain.data, vdata->data, plain.size) != 0) - { - gnutls_assert (); - _gnutls_free_datum (&plain); - return GNUTLS_E_PK_SIG_VERIFY_FAILED; - } - - _gnutls_free_datum (&plain); - - return 0; /* ok */ -} - /* encodes the Dss-Sig-Value structure */ int @@ -506,3 +194,172 @@ _gnutls_pk_get_hash_algorithm (gnutls_pk_algorithm_t pk, NULL, pk, params); } + +/* Writes the digest information and the digest in a DER encoded + * structure. The digest info is allocated and stored into the info structure. + */ +int +encode_ber_digest_info (gnutls_digest_algorithm_t hash, + const gnutls_datum_t * digest, + gnutls_datum_t * output) +{ + ASN1_TYPE dinfo = ASN1_TYPE_EMPTY; + int result; + const char *algo; + uint8_t *tmp_output; + int tmp_output_size; + + algo = _gnutls_x509_mac_to_oid ((gnutls_mac_algorithm_t) hash); + if (algo == NULL) + { + gnutls_assert (); + _gnutls_debug_log ("Hash algorithm: %d has no OID\n", hash); + return GNUTLS_E_UNKNOWN_PK_ALGORITHM; + } + + if ((result = asn1_create_element (_gnutls_get_gnutls_asn (), + "GNUTLS.DigestInfo", + &dinfo)) != ASN1_SUCCESS) + { + gnutls_assert (); + return _gnutls_asn2err (result); + } + + result = asn1_write_value (dinfo, "digestAlgorithm.algorithm", algo, 1); + if (result != ASN1_SUCCESS) + { + gnutls_assert (); + asn1_delete_structure (&dinfo); + return _gnutls_asn2err (result); + } + + /* Write an ASN.1 NULL in the parameters field. This matches RFC + 3279 and RFC 4055, although is arguable incorrect from a historic + perspective (see those documents for more information). + Regardless of what is correct, this appears to be what most + implementations do. */ + result = asn1_write_value (dinfo, "digestAlgorithm.parameters", + ASN1_NULL, ASN1_NULL_SIZE); + if (result != ASN1_SUCCESS) + { + gnutls_assert (); + asn1_delete_structure (&dinfo); + return _gnutls_asn2err (result); + } + + result = asn1_write_value (dinfo, "digest", digest->data, digest->size); + if (result != ASN1_SUCCESS) + { + gnutls_assert (); + asn1_delete_structure (&dinfo); + return _gnutls_asn2err (result); + } + + tmp_output_size = 0; + asn1_der_coding (dinfo, "", NULL, &tmp_output_size, NULL); + + tmp_output = gnutls_malloc (tmp_output_size); + if (tmp_output == NULL) + { + gnutls_assert (); + asn1_delete_structure (&dinfo); + return GNUTLS_E_MEMORY_ERROR; + } + + result = asn1_der_coding (dinfo, "", tmp_output, &tmp_output_size, NULL); + if (result != ASN1_SUCCESS) + { + gnutls_assert (); + asn1_delete_structure (&dinfo); + return _gnutls_asn2err (result); + } + + asn1_delete_structure (&dinfo); + + output->size = tmp_output_size; + output->data = tmp_output; + + return 0; +} + +/* Reads the digest information. + * we use DER here, although we should use BER. It works fine + * anyway. + */ +int +decode_ber_digest_info (const gnutls_datum_t * info, + gnutls_digest_algorithm_t * hash, + uint8_t * digest, unsigned int *digest_size) +{ + ASN1_TYPE dinfo = ASN1_TYPE_EMPTY; + int result; + char str[1024]; + int len; + + if ((result = asn1_create_element (_gnutls_get_gnutls_asn (), + "GNUTLS.DigestInfo", + &dinfo)) != ASN1_SUCCESS) + { + gnutls_assert (); + return _gnutls_asn2err (result); + } + + result = asn1_der_decoding (&dinfo, info->data, info->size, NULL); + if (result != ASN1_SUCCESS) + { + gnutls_assert (); + asn1_delete_structure (&dinfo); + return _gnutls_asn2err (result); + } + + len = sizeof (str) - 1; + result = asn1_read_value (dinfo, "digestAlgorithm.algorithm", str, &len); + if (result != ASN1_SUCCESS) + { + gnutls_assert (); + asn1_delete_structure (&dinfo); + return _gnutls_asn2err (result); + } + + *hash = _gnutls_x509_oid_to_digest (str); + + if (*hash == GNUTLS_DIG_UNKNOWN) + { + + _gnutls_debug_log ("verify.c: HASH OID: %s\n", str); + + gnutls_assert (); + asn1_delete_structure (&dinfo); + return GNUTLS_E_UNKNOWN_ALGORITHM; + } + + len = sizeof (str) - 1; + result = asn1_read_value (dinfo, "digestAlgorithm.parameters", str, &len); + /* To avoid permitting garbage in the parameters field, either the + parameters field is not present, or it contains 0x05 0x00. */ + if (!(result == ASN1_ELEMENT_NOT_FOUND || + (result == ASN1_SUCCESS && len == ASN1_NULL_SIZE && + memcmp (str, ASN1_NULL, ASN1_NULL_SIZE) == 0))) + { + gnutls_assert (); + asn1_delete_structure (&dinfo); + return GNUTLS_E_ASN1_GENERIC_ERROR; + } + + len = *digest_size; + result = asn1_read_value (dinfo, "digest", digest, &len); + + if (result != ASN1_SUCCESS) + { + gnutls_assert (); + *digest_size = len; + asn1_delete_structure (&dinfo); + return _gnutls_asn2err (result); + } + + *digest_size = len; + asn1_delete_structure (&dinfo); + + return 0; +} + diff --git a/lib/gnutls_pk.h b/lib/gnutls_pk.h index 189c61c333..ee2b80bf7b 100644 --- a/lib/gnutls_pk.h +++ b/lib/gnutls_pk.h @@ -33,6 +33,7 @@ extern gnutls_crypto_pk_st _gnutls_pk_ops; #define _gnutls_pk_verify_params( algo, params) _gnutls_pk_ops.verify_params( algo, params) #define _gnutls_pk_derive( algo, out, pub, priv) _gnutls_pk_ops.derive( algo, out, pub, priv) #define _gnutls_pk_generate( algo, bits, priv) _gnutls_pk_ops.generate( algo, bits, priv) +#define _gnutls_pk_hash_algorithm( pk, sig, params, hash) _gnutls_pk_ops.hash_algorithm(pk, sig, params, hash) inline static int _gnutls_pk_fixup (gnutls_pk_algorithm_t algo, gnutls_direction_t direction, @@ -46,19 +47,6 @@ _gnutls_pk_fixup (gnutls_pk_algorithm_t algo, gnutls_direction_t direction, int _gnutls_pk_params_copy (gnutls_pk_params_st * dst, const gnutls_pk_params_st * src); /* The internal PK interface */ -int _gnutls_pkcs1_rsa_encrypt (gnutls_datum_t * ciphertext, - const gnutls_datum_t * plaintext, - gnutls_pk_params_st * params, - unsigned btype); -int _gnutls_pkcs1_rsa_decrypt (gnutls_datum_t * plaintext, - const gnutls_datum_t * ciphertext, - gnutls_pk_params_st* params, - unsigned btype); -int _gnutls_rsa_verify (const gnutls_datum_t * vdata, - const gnutls_datum_t * ciphertext, - gnutls_pk_params_st*, - int btype); - int _gnutls_encode_ber_rs (gnutls_datum_t * sig_value, bigint_t r, bigint_t s); @@ -66,6 +54,16 @@ int _gnutls_decode_ber_rs (const gnutls_datum_t * sig_value, bigint_t * r, bigint_t * s); +int +encode_ber_digest_info (gnutls_digest_algorithm_t hash, + const gnutls_datum_t * digest, + gnutls_datum_t * output); + +int +decode_ber_digest_info (const gnutls_datum_t * info, + gnutls_digest_algorithm_t * hash, + uint8_t * digest, unsigned int *digest_size); + int _gnutls_pk_get_hash_algorithm (gnutls_pk_algorithm_t pk, gnutls_pk_params_st*, gnutls_digest_algorithm_t * dig, diff --git a/lib/gnutls_privkey.c b/lib/gnutls_privkey.c index 9cb820ed56..3b4446350b 100644 --- a/lib/gnutls_privkey.c +++ b/lib/gnutls_privkey.c @@ -562,7 +562,7 @@ uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE]; * together with a hash functions. Different hash functions may be * used for the RSA algorithm, but only the SHA family for the DSA keys. * - * Use gnutls_pubkey_get_preferred_hash_algorithm() to determine + * You may use gnutls_pubkey_get_preferred_hash_algorithm() to determine * the hash algorithm. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a @@ -623,7 +623,7 @@ cleanup: * together with a hash functions. Different hash functions may be * used for the RSA algorithm, but only SHA-XXX for the DSA keys. * - * Use gnutls_pubkey_get_preferred_hash_algorithm() to determine + * You may use gnutls_pubkey_get_preferred_hash_algorithm() to determine * the hash algorithm. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a @@ -701,9 +701,8 @@ _gnutls_privkey_sign_hash (gnutls_privkey_t key, hash, signature); #endif case GNUTLS_PRIVKEY_X509: - return _gnutls_soft_sign (key->key.x509->pk_algorithm, - &key->key.x509->params, - hash, signature); + return _gnutls_pk_sign (key->key.x509->pk_algorithm, + signature, hash, &key->key.x509->params); case GNUTLS_PRIVKEY_EXT: if (key->key.ext.sign_func == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); @@ -735,23 +734,16 @@ gnutls_privkey_decrypt_data (gnutls_privkey_t key, const gnutls_datum_t * ciphertext, gnutls_datum_t * plaintext) { - if (key->pk_algorithm != GNUTLS_PK_RSA) - { - gnutls_assert (); - return GNUTLS_E_INVALID_REQUEST; - } - switch (key->type) { #ifdef ENABLE_OPENPGP case GNUTLS_PRIVKEY_OPENPGP: return _gnutls_openpgp_privkey_decrypt_data (key->key.openpgp, flags, - ciphertext, plaintext); + ciphertext, plaintext); #endif case GNUTLS_PRIVKEY_X509: - return _gnutls_pkcs1_rsa_decrypt (plaintext, ciphertext, - &key->key.x509->params, - 2); + return _gnutls_pk_decrypt (key->pk_algorithm, plaintext, ciphertext, + &key->key.x509->params); #ifdef ENABLE_PKCS11 case GNUTLS_PRIVKEY_PKCS11: return _gnutls_pkcs11_privkey_decrypt_data (key->key.pkcs11, diff --git a/lib/gnutls_pubkey.c b/lib/gnutls_pubkey.c index 6496537ca7..ab7a667264 100644 --- a/lib/gnutls_pubkey.c +++ b/lib/gnutls_pubkey.c @@ -1,5 +1,5 @@ /* - * GnuTLS PKCS#11 support + * GnuTLS public key support * Copyright (C) 2010-2012 Free Software Foundation, Inc. * * Author: Nikos Mavrogiannopoulos @@ -1305,7 +1305,8 @@ gnutls_pubkey_import_dsa_raw (gnutls_pubkey_t key, * parameters from the certificate. * * Returns: In case of a verification failure %GNUTLS_E_PK_SIG_VERIFY_FAILED - * is returned, and zero or positive code on success. + * is returned, and zero or positive code on success. Use gnutls_pubkey_verify_data2() + * instead of this function. * * Since: 2.12.0 **/ @@ -1350,10 +1351,10 @@ gnutls_pubkey_verify_data (gnutls_pubkey_t pubkey, unsigned int flags, **/ int gnutls_pubkey_verify_data2 (gnutls_pubkey_t pubkey, - gnutls_sign_algorithm_t algo, - unsigned int flags, - const gnutls_datum_t * data, - const gnutls_datum_t * signature) + gnutls_sign_algorithm_t algo, + unsigned int flags, + const gnutls_datum_t * data, + const gnutls_datum_t * signature) { int ret; @@ -1363,8 +1364,8 @@ gnutls_pubkey_verify_data2 (gnutls_pubkey_t pubkey, return GNUTLS_E_INVALID_REQUEST; } - ret = pubkey_verify_data( pubkey->pk_algorithm, _gnutls_sign_get_hash_algorithm(algo), data, signature, - &pubkey->params); + ret = pubkey_verify_data( pubkey->pk_algorithm, _gnutls_sign_get_hash_algorithm(algo), + data, signature, &pubkey->params); if (ret < 0) { gnutls_assert(); @@ -1382,7 +1383,8 @@ gnutls_pubkey_verify_data2 (gnutls_pubkey_t pubkey, * @signature: contains the signature * * This function will verify the given signed digest, using the - * parameters from the public key. + * parameters from the public key. Use gnutls_pubkey_verify_hash2() + * instead of this function. * * Returns: In case of a verification failure %GNUTLS_E_PK_SIG_VERIFY_FAILED * is returned, and zero or positive code on success. @@ -1393,6 +1395,40 @@ int gnutls_pubkey_verify_hash (gnutls_pubkey_t key, unsigned int flags, const gnutls_datum_t * hash, const gnutls_datum_t * signature) +{ +gnutls_digest_algorithm_t algo; +int ret; + + ret = gnutls_pubkey_get_verify_algorithm (key, signature, &algo); + if (ret < 0) + return gnutls_assert_val(ret); + + return gnutls_pubkey_verify_hash2(key, gnutls_pk_to_sign(key->pk_algorithm, algo), + flags, hash, signature); +} + +/** + * gnutls_pubkey_verify_hash2: + * @key: Holds the public key + * @algo: The signature algorithm used + * @flags: should be 0 for now + * @hash: holds the hash digest to be verified + * @signature: contains the signature + * + * This function will verify the given signed digest, using the + * parameters from the public key. + * + * Returns: In case of a verification failure %GNUTLS_E_PK_SIG_VERIFY_FAILED + * is returned, and zero or positive code on success. + * + * Since: 3.0 + **/ +int +gnutls_pubkey_verify_hash2 (gnutls_pubkey_t key, + gnutls_sign_algorithm_t algo, + unsigned int flags, + const gnutls_datum_t * hash, + const gnutls_datum_t * signature) { if (key == NULL) { @@ -1401,11 +1437,11 @@ gnutls_pubkey_verify_hash (gnutls_pubkey_t key, unsigned int flags, } if (flags & GNUTLS_PUBKEY_VERIFY_FLAG_TLS_RSA) - return _gnutls_rsa_verify (hash, signature, &key->params, 1); + return _gnutls_pk_verify (GNUTLS_PK_RSA, hash, signature, &key->params); else { - return pubkey_verify_hashed_data (key->pk_algorithm, hash, signature, - &key->params); + return pubkey_verify_hashed_data (key->pk_algorithm, _gnutls_sign_get_hash_algorithm(algo), + hash, signature, &key->params); } } @@ -1426,18 +1462,17 @@ gnutls_pubkey_verify_hash (gnutls_pubkey_t key, unsigned int flags, **/ int gnutls_pubkey_encrypt_data (gnutls_pubkey_t key, unsigned int flags, - const gnutls_datum_t * plaintext, - gnutls_datum_t * ciphertext) + const gnutls_datum_t * plaintext, + gnutls_datum_t * ciphertext) { - if (key == NULL || key->pk_algorithm != GNUTLS_PK_RSA) + if (key == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } - return _gnutls_pkcs1_rsa_encrypt (ciphertext, plaintext, - &key->params, - 2); + return _gnutls_pk_encrypt (key->pk_algorithm, ciphertext, + plaintext, &key->params); } /** @@ -1535,48 +1570,24 @@ _gnutls_pubkey_get_mpis (gnutls_pubkey_t key, * params[1] is public key */ static int -_pkcs1_rsa_verify_sig (const gnutls_datum_t * text, +_pkcs1_rsa_verify_sig (gnutls_digest_algorithm_t hash, + const gnutls_datum_t * text, const gnutls_datum_t * prehash, const gnutls_datum_t * signature, gnutls_pk_params_st * params) { - gnutls_digest_algorithm_t hash = GNUTLS_DIG_UNKNOWN; int ret; - uint8_t digest[MAX_HASH_SIZE], md[MAX_HASH_SIZE], *cmp; + uint8_t md[MAX_HASH_SIZE], *cmp; unsigned int digest_size; + gnutls_datum_t d, di; digest_hd_st hd; - gnutls_datum_t decrypted; - ret = - _gnutls_pkcs1_rsa_decrypt (&decrypted, signature, params, 1); - if (ret < 0) + digest_size = _gnutls_hash_get_algo_len (hash); + if (prehash) { - gnutls_assert (); - return ret; - } - - /* decrypted is a BER encoded data of type DigestInfo - */ - - digest_size = sizeof (digest); - if ((ret = - decode_ber_digest_info (&decrypted, &hash, digest, &digest_size)) != 0) - { - gnutls_assert (); - _gnutls_free_datum (&decrypted); - return ret; - } - - _gnutls_free_datum (&decrypted); - - if (digest_size != _gnutls_hash_get_algo_len (hash)) - { - gnutls_assert (); - return GNUTLS_E_ASN1_GENERIC_ERROR; - } + if (prehash->data == NULL || prehash->size != digest_size) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); - if (prehash && prehash->data && prehash->size == digest_size) - { cmp = prehash->data; } else @@ -1599,29 +1610,39 @@ _pkcs1_rsa_verify_sig (const gnutls_datum_t * text, cmp = md; } + + d.data = cmp; + d.size = digest_size; - if (memcmp (cmp, digest, digest_size) != 0) - { - gnutls_assert (); - return GNUTLS_E_PK_SIG_VERIFY_FAILED; - } + /* decrypted is a BER encoded data of type DigestInfo + */ - return 0; + ret = encode_ber_digest_info (hash, &d, &di); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _gnutls_pk_verify (GNUTLS_PK_RSA, &di, signature, params); + + _gnutls_free_datum (&di); + + return ret; } /* Hashes input data and verifies a signature. */ static int -dsa_verify_hashed_data (const gnutls_datum_t * hash, +dsa_verify_hashed_data (gnutls_pk_algorithm_t pk, + gnutls_digest_algorithm_t algo, + const gnutls_datum_t * hash, const gnutls_datum_t * signature, - gnutls_pk_algorithm_t pk, gnutls_pk_params_st* params) { gnutls_datum_t digest; - unsigned int algo; unsigned int hash_len; - algo = _gnutls_dsa_q_to_hash (pk, params, &hash_len); + if (algo == GNUTLS_DIG_UNKNOWN) + algo = _gnutls_dsa_q_to_hash (pk, params, &hash_len); + else hash_len = _gnutls_hash_get_algo_len(algo); /* SHA1 or better allowed */ if (!hash->data || hash->size < hash_len) @@ -1672,9 +1693,10 @@ dsa_verify_data (gnutls_pk_algorithm_t pk, */ int pubkey_verify_hashed_data (gnutls_pk_algorithm_t pk, - const gnutls_datum_t * hash, - const gnutls_datum_t * signature, - gnutls_pk_params_st * issuer_params) + gnutls_digest_algorithm_t hash_algo, + const gnutls_datum_t * hash, + const gnutls_datum_t * signature, + gnutls_pk_params_st * issuer_params) { switch (pk) @@ -1682,7 +1704,7 @@ pubkey_verify_hashed_data (gnutls_pk_algorithm_t pk, case GNUTLS_PK_RSA: if (_pkcs1_rsa_verify_sig - (NULL, hash, signature, issuer_params) != 0) + (hash_algo, NULL, hash, signature, issuer_params) != 0) { gnutls_assert (); return GNUTLS_E_PK_SIG_VERIFY_FAILED; @@ -1693,7 +1715,7 @@ pubkey_verify_hashed_data (gnutls_pk_algorithm_t pk, case GNUTLS_PK_EC: case GNUTLS_PK_DSA: - if (dsa_verify_hashed_data(hash, signature, pk, issuer_params) != 0) + if (dsa_verify_hashed_data(pk, hash_algo, hash, signature, issuer_params) != 0) { gnutls_assert (); return GNUTLS_E_PK_SIG_VERIFY_FAILED; @@ -1713,7 +1735,7 @@ pubkey_verify_hashed_data (gnutls_pk_algorithm_t pk, */ int pubkey_verify_data (gnutls_pk_algorithm_t pk, - gnutls_digest_algorithm_t algo, + gnutls_digest_algorithm_t hash_algo, const gnutls_datum_t * data, const gnutls_datum_t * signature, gnutls_pk_params_st * issuer_params) @@ -1724,7 +1746,7 @@ pubkey_verify_data (gnutls_pk_algorithm_t pk, case GNUTLS_PK_RSA: if (_pkcs1_rsa_verify_sig - (data, NULL, signature, issuer_params) != 0) + (hash_algo, data, NULL, signature, issuer_params) != 0) { gnutls_assert (); return GNUTLS_E_PK_SIG_VERIFY_FAILED; @@ -1735,7 +1757,7 @@ pubkey_verify_data (gnutls_pk_algorithm_t pk, case GNUTLS_PK_EC: case GNUTLS_PK_DSA: - if (dsa_verify_data(pk, algo, data, signature, issuer_params) != 0) + if (dsa_verify_data(pk, hash_algo, data, signature, issuer_params) != 0) { gnutls_assert (); return GNUTLS_E_PK_SIG_VERIFY_FAILED; diff --git a/lib/gnutls_sig.c b/lib/gnutls_sig.c index afed87ffb0..c576655e10 100644 --- a/lib/gnutls_sig.c +++ b/lib/gnutls_sig.c @@ -45,10 +45,6 @@ sign_tls_hash (gnutls_session_t session, gnutls_digest_algorithm_t hash_algo, const gnutls_datum_t * hash_concat, gnutls_datum_t * signature); -static int -encode_ber_digest_info (gnutls_digest_algorithm_t hash, - const gnutls_datum_t * digest, - gnutls_datum_t * output); /* While this is currently equal to the length of RSA/SHA512 * signature, it should also be sufficient for DSS signature and any @@ -163,41 +159,6 @@ _gnutls_handshake_sign_data (gnutls_session_t session, gnutls_pcert_st* cert, } - -/* This will create a PKCS1 or DSA signature, using the given parameters, and the - * given data. The output will be allocated and be put in signature. - */ -int -_gnutls_soft_sign (gnutls_pk_algorithm_t algo, gnutls_pk_params_st * params, - const gnutls_datum_t * data, - gnutls_datum_t * signature) -{ - int ret; - - switch (algo) - { - case GNUTLS_PK_RSA: - /* encrypt */ - if ((ret = _gnutls_pkcs1_rsa_encrypt (signature, data, params, 1)) < 0) - { - gnutls_assert (); - return ret; - } - - break; - default: - ret = _gnutls_pk_sign( algo, signature, data, params); - if (ret < 0) - { - gnutls_assert (); - return ret; - } - break; - } - - return 0; -} - /* This will create a PKCS1 or DSA signature, as defined in the TLS protocol. * Cert is the certificate of the corresponding private key. It is only checked if * it supports signing. @@ -270,9 +231,10 @@ es_cleanup: static int verify_tls_hash (gnutls_protocol_t ver, gnutls_pcert_st* cert, - const gnutls_datum_t * hash_concat, - gnutls_datum_t * signature, size_t sha1pos, - gnutls_pk_algorithm_t pk_algo) + const gnutls_datum_t * hash_concat, + gnutls_datum_t * signature, size_t sha1pos, + gnutls_sign_algorithm_t sign_algo, + gnutls_pk_algorithm_t pk_algo) { int ret; gnutls_datum_t vdata; @@ -309,12 +271,9 @@ verify_tls_hash (gnutls_protocol_t ver, gnutls_pcert_st* cert, flags = GNUTLS_PUBKEY_VERIFY_FLAG_TLS_RSA; else flags = 0; - - break; case GNUTLS_PK_DSA: case GNUTLS_PK_EC: - vdata.data = &hash_concat->data[sha1pos]; vdata.size = hash_concat->size - sha1pos; @@ -326,8 +285,8 @@ verify_tls_hash (gnutls_protocol_t ver, gnutls_pcert_st* cert, return GNUTLS_E_INTERNAL_ERROR; } - ret = gnutls_pubkey_verify_hash(cert->pubkey, flags, &vdata, - signature); + ret = gnutls_pubkey_verify_hash2(cert->pubkey, sign_algo, flags, + &vdata, signature); if (ret < 0) return gnutls_assert_val(ret); @@ -344,7 +303,7 @@ int _gnutls_handshake_verify_data (gnutls_session_t session, gnutls_pcert_st* cert, const gnutls_datum_t * params, gnutls_datum_t * signature, - gnutls_sign_algorithm_t algo) + gnutls_sign_algorithm_t sign_algo) { gnutls_datum_t dconcat; int ret; @@ -357,17 +316,17 @@ _gnutls_handshake_verify_data (gnutls_session_t session, gnutls_pcert_st* cert, if (_gnutls_version_has_selectable_sighash (ver)) { _gnutls_handshake_log ("HSK[%p]: verify handshake data: using %s\n", - session, gnutls_sign_algorithm_get_name (algo)); + session, gnutls_sign_algorithm_get_name (sign_algo)); - ret = _gnutls_pubkey_compatible_with_sig(cert->pubkey, ver, algo); + ret = _gnutls_pubkey_compatible_with_sig(cert->pubkey, ver, sign_algo); if (ret < 0) return gnutls_assert_val(ret); - ret = _gnutls_session_sign_algo_enabled (session, algo); + ret = _gnutls_session_sign_algo_enabled (session, sign_algo); if (ret < 0) return gnutls_assert_val(ret); - hash_algo = _gnutls_sign_get_hash_algorithm (algo); + hash_algo = _gnutls_sign_get_hash_algorithm (sign_algo); } else { @@ -420,7 +379,8 @@ _gnutls_handshake_verify_data (gnutls_session_t session, gnutls_pcert_st* cert, ret = verify_tls_hash (ver, cert, &dconcat, signature, dconcat.size - _gnutls_hash_get_algo_len (hash_algo), - _gnutls_sign_get_pk_algorithm (algo)); + sign_algo, + _gnutls_sign_get_pk_algorithm (sign_algo)); if (ret < 0) { gnutls_assert (); @@ -465,7 +425,7 @@ _gnutls_handshake_verify_crt_vrfy12 (gnutls_session_t session, dconcat.size = _gnutls_hash_get_algo_len (hash_algo); ret = - verify_tls_hash (ver, cert, &dconcat, signature, 0, pk); + verify_tls_hash (ver, cert, &dconcat, signature, 0, sign_algo, pk); if (ret < 0) { gnutls_assert (); @@ -498,7 +458,7 @@ _gnutls_handshake_verify_crt_vrfy (gnutls_session_t session, if (_gnutls_version_has_selectable_sighash(ver)) return _gnutls_handshake_verify_crt_vrfy12 (session, cert, signature, - sign_algo); + sign_algo); ret = _gnutls_hash_init (&td_md5, GNUTLS_DIG_MD5); @@ -560,7 +520,8 @@ _gnutls_handshake_verify_crt_vrfy (gnutls_session_t session, ret = verify_tls_hash (ver, cert, &dconcat, signature, 16, - gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL)); + GNUTLS_SIGN_UNKNOWN, + gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL)); if (ret < 0) { gnutls_assert (); @@ -788,170 +749,3 @@ pk_prepare_hash (gnutls_pk_algorithm_t pk, return 0; } -/* Reads the digest information. - * we use DER here, although we should use BER. It works fine - * anyway. - */ -int -decode_ber_digest_info (const gnutls_datum_t * info, - gnutls_digest_algorithm_t * hash, - uint8_t * digest, unsigned int *digest_size) -{ - ASN1_TYPE dinfo = ASN1_TYPE_EMPTY; - int result; - char str[1024]; - int len; - - if ((result = asn1_create_element (_gnutls_get_gnutls_asn (), - "GNUTLS.DigestInfo", - &dinfo)) != ASN1_SUCCESS) - { - gnutls_assert (); - return _gnutls_asn2err (result); - } - - result = asn1_der_decoding (&dinfo, info->data, info->size, NULL); - if (result != ASN1_SUCCESS) - { - gnutls_assert (); - asn1_delete_structure (&dinfo); - return _gnutls_asn2err (result); - } - - len = sizeof (str) - 1; - result = asn1_read_value (dinfo, "digestAlgorithm.algorithm", str, &len); - if (result != ASN1_SUCCESS) - { - gnutls_assert (); - asn1_delete_structure (&dinfo); - return _gnutls_asn2err (result); - } - - *hash = _gnutls_x509_oid_to_digest (str); - - if (*hash == GNUTLS_DIG_UNKNOWN) - { - - _gnutls_debug_log ("verify.c: HASH OID: %s\n", str); - - gnutls_assert (); - asn1_delete_structure (&dinfo); - return GNUTLS_E_UNKNOWN_ALGORITHM; - } - - len = sizeof (str) - 1; - result = asn1_read_value (dinfo, "digestAlgorithm.parameters", str, &len); - /* To avoid permitting garbage in the parameters field, either the - parameters field is not present, or it contains 0x05 0x00. */ - if (!(result == ASN1_ELEMENT_NOT_FOUND || - (result == ASN1_SUCCESS && len == ASN1_NULL_SIZE && - memcmp (str, ASN1_NULL, ASN1_NULL_SIZE) == 0))) - { - gnutls_assert (); - asn1_delete_structure (&dinfo); - return GNUTLS_E_ASN1_GENERIC_ERROR; - } - - len = *digest_size; - result = asn1_read_value (dinfo, "digest", digest, &len); - - if (result != ASN1_SUCCESS) - { - gnutls_assert (); - *digest_size = len; - asn1_delete_structure (&dinfo); - return _gnutls_asn2err (result); - } - - *digest_size = len; - asn1_delete_structure (&dinfo); - - return 0; -} - -/* Writes the digest information and the digest in a DER encoded - * structure. The digest info is allocated and stored into the info structure. - */ -static int -encode_ber_digest_info (gnutls_digest_algorithm_t hash, - const gnutls_datum_t * digest, - gnutls_datum_t * output) -{ - ASN1_TYPE dinfo = ASN1_TYPE_EMPTY; - int result; - const char *algo; - uint8_t *tmp_output; - int tmp_output_size; - - algo = _gnutls_x509_mac_to_oid ((gnutls_mac_algorithm_t) hash); - if (algo == NULL) - { - gnutls_assert (); - _gnutls_debug_log ("Hash algorithm: %d has no OID\n", hash); - return GNUTLS_E_UNKNOWN_PK_ALGORITHM; - } - - if ((result = asn1_create_element (_gnutls_get_gnutls_asn (), - "GNUTLS.DigestInfo", - &dinfo)) != ASN1_SUCCESS) - { - gnutls_assert (); - return _gnutls_asn2err (result); - } - - result = asn1_write_value (dinfo, "digestAlgorithm.algorithm", algo, 1); - if (result != ASN1_SUCCESS) - { - gnutls_assert (); - asn1_delete_structure (&dinfo); - return _gnutls_asn2err (result); - } - - /* Write an ASN.1 NULL in the parameters field. This matches RFC - 3279 and RFC 4055, although is arguable incorrect from a historic - perspective (see those documents for more information). - Regardless of what is correct, this appears to be what most - implementations do. */ - result = asn1_write_value (dinfo, "digestAlgorithm.parameters", - ASN1_NULL, ASN1_NULL_SIZE); - if (result != ASN1_SUCCESS) - { - gnutls_assert (); - asn1_delete_structure (&dinfo); - return _gnutls_asn2err (result); - } - - result = asn1_write_value (dinfo, "digest", digest->data, digest->size); - if (result != ASN1_SUCCESS) - { - gnutls_assert (); - asn1_delete_structure (&dinfo); - return _gnutls_asn2err (result); - } - - tmp_output_size = 0; - asn1_der_coding (dinfo, "", NULL, &tmp_output_size, NULL); - - tmp_output = gnutls_malloc (tmp_output_size); - if (output->data == NULL) - { - gnutls_assert (); - asn1_delete_structure (&dinfo); - return GNUTLS_E_MEMORY_ERROR; - } - - result = asn1_der_coding (dinfo, "", tmp_output, &tmp_output_size, NULL); - if (result != ASN1_SUCCESS) - { - gnutls_assert (); - asn1_delete_structure (&dinfo); - return _gnutls_asn2err (result); - } - - asn1_delete_structure (&dinfo); - - output->size = tmp_output_size; - output->data = tmp_output; - - return 0; -} diff --git a/lib/gnutls_sig.h b/lib/gnutls_sig.h index cd4981d945..25ef26a5c2 100644 --- a/lib/gnutls_sig.h +++ b/lib/gnutls_sig.h @@ -48,11 +48,6 @@ int _gnutls_handshake_verify_data (gnutls_session_t session, gnutls_datum_t * signature, gnutls_sign_algorithm_t algo); -int _gnutls_soft_sign (gnutls_pk_algorithm_t algo, - gnutls_pk_params_st* params, - const gnutls_datum_t * data, - gnutls_datum_t * signature); - int pk_prepare_hash (gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t hash, gnutls_datum_t * output); int pk_hash_data (gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t hash, @@ -64,9 +59,5 @@ _gnutls_privkey_sign_hash (gnutls_privkey_t key, const gnutls_datum_t * hash, gnutls_datum_t * signature); -int -decode_ber_digest_info (const gnutls_datum_t * info, - gnutls_digest_algorithm_t * hash, - uint8_t * digest, unsigned int *digest_size); #endif diff --git a/lib/includes/gnutls/abstract.h b/lib/includes/gnutls/abstract.h index b89da86c30..a99c92cb66 100644 --- a/lib/includes/gnutls/abstract.h +++ b/lib/includes/gnutls/abstract.h @@ -141,6 +141,13 @@ gnutls_pubkey_verify_hash (gnutls_pubkey_t key, unsigned int flags, const gnutls_datum_t * hash, const gnutls_datum_t * signature); int +gnutls_pubkey_verify_hash2 (gnutls_pubkey_t key, + gnutls_sign_algorithm_t algo, + unsigned int flags, + const gnutls_datum_t * hash, + const gnutls_datum_t * signature); + +int gnutls_pubkey_get_verify_algorithm (gnutls_pubkey_t key, const gnutls_datum_t * signature, gnutls_digest_algorithm_t * hash); diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index e9d92fd507..50cc22df22 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -770,10 +770,11 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session); gnutls_cipher_algorithm_t gnutls_cipher_get (gnutls_session_t session); gnutls_kx_algorithm_t gnutls_kx_get (gnutls_session_t session); gnutls_mac_algorithm_t gnutls_mac_get (gnutls_session_t session); - gnutls_compression_method_t + gnutls_compression_method_t gnutls_compression_get (gnutls_session_t session); - gnutls_certificate_type_t + gnutls_certificate_type_t gnutls_certificate_type_get (gnutls_session_t session); + int gnutls_sign_algorithm_get_requested (gnutls_session_t session, size_t indx, gnutls_sign_algorithm_t * algo); @@ -791,6 +792,10 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session); type); const char *gnutls_pk_get_name (gnutls_pk_algorithm_t algorithm); const char *gnutls_sign_get_name (gnutls_sign_algorithm_t algorithm); + + gnutls_sign_algorithm_t gnutls_pk_to_sign (gnutls_pk_algorithm_t pk, + gnutls_digest_algorithm_t d); + #define gnutls_sign_algorithm_get_name gnutls_sign_get_name gnutls_mac_algorithm_t gnutls_mac_get_id (const char *name); diff --git a/lib/libgnutls.map b/lib/libgnutls.map index c7385ad5d1..7498633734 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -795,6 +795,8 @@ GNUTLS_3_1_0 { gnutls_x509_trust_list_add_system_trust; gnutls_x509_trust_list_add_trust_file; gnutls_x509_trust_list_add_trust_mem; + gnutls_pubkey_verify_hash2; + gnutls_pk_to_sign; } GNUTLS_3_0_0; GNUTLS_PRIVATE { diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c index d7e9a057cc..5932188c6d 100644 --- a/lib/nettle/pk.c +++ b/lib/nettle/pk.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -78,7 +79,16 @@ _rsa_params_to_privkey (const gnutls_pk_params_st * pk_params, memcpy (&priv->c, pk_params->params[5], sizeof (mpz_t)); memcpy (&priv->a, pk_params->params[6], sizeof (mpz_t)); memcpy (&priv->b, pk_params->params[7], sizeof (mpz_t)); + priv->size = nettle_mpz_sizeinbase_256_u(TOMPZ(pk_params->params[RSA_MODULUS])); +} +static void +_rsa_params_to_pubkey (const gnutls_pk_params_st * pk_params, + struct rsa_public_key *pub) +{ + memcpy (&pub->n, pk_params->params[RSA_MODULUS], sizeof (mpz_t)); + memcpy (&pub->e, pk_params->params[RSA_PUB], sizeof (mpz_t)); + pub->size = nettle_mpz_sizeinbase_256_u(pub->n); } static void @@ -192,25 +202,26 @@ _wrap_nettle_pk_encrypt (gnutls_pk_algorithm_t algo, const gnutls_pk_params_st * pk_params) { int ret; + mpz_t p; + + mpz_init(p); switch (algo) { case GNUTLS_PK_RSA: { - bigint_t p; + struct rsa_public_key pub; + + _rsa_params_to_pubkey (pk_params, &pub); - if (_gnutls_mpi_scan_nz (&p, plaintext->data, plaintext->size) != 0) + ret = rsa_encrypt(&pub, NULL, rnd_func, plaintext->size, plaintext->data, p); + if (ret == 0) { - gnutls_assert (); - return GNUTLS_E_MPI_SCAN_FAILED; + ret = gnutls_assert_val(GNUTLS_E_ENCRYPTION_FAILED); + goto cleanup; } - mpz_powm (p, p, TOMPZ (pk_params->params[1]) /*e */ , - TOMPZ (pk_params->params[0] /*m */ )); - ret = _gnutls_mpi_dprint_size (p, ciphertext, plaintext->size); - _gnutls_mpi_release (&p); - if (ret < 0) { gnutls_assert (); @@ -229,74 +240,10 @@ _wrap_nettle_pk_encrypt (gnutls_pk_algorithm_t algo, cleanup: + mpz_clear(p); return ret; } -/* returns the blinded c and the inverse of a random - * number r; - */ -static bigint_t -rsa_blind (bigint_t c, bigint_t e, bigint_t n, bigint_t * _ri) -{ - bigint_t nc = NULL, r = NULL, ri = NULL; - - /* nc = c*(r^e) - * ri = r^(-1) - */ - nc = _gnutls_mpi_alloc_like (n); - if (nc == NULL) - { - gnutls_assert (); - return NULL; - } - - ri = _gnutls_mpi_alloc_like (n); - if (nc == NULL) - { - gnutls_assert (); - goto fail; - } - - r = _gnutls_mpi_randomize (NULL, _gnutls_mpi_get_nbits (n), - GNUTLS_RND_NONCE); - if (r == NULL) - { - gnutls_assert (); - goto fail; - } - - /* invert r */ - if (mpz_invert (ri, r, n) == 0) - { - gnutls_assert (); - goto fail; - } - - /* r = r^e */ - - _gnutls_mpi_powm (r, r, e, n); - - _gnutls_mpi_mulm (nc, c, r, n); - - *_ri = ri; - - _gnutls_mpi_release (&r); - - return nc; -fail: - _gnutls_mpi_release (&nc); - _gnutls_mpi_release (&r); - return NULL; -} - -/* c = c*ri mod n - */ -static inline void -rsa_unblind (bigint_t c, bigint_t ri, bigint_t n) -{ - _gnutls_mpi_mulm (c, c, ri, n); -} - static int _wrap_nettle_pk_decrypt (gnutls_pk_algorithm_t algo, gnutls_datum_t * plaintext, @@ -305,44 +252,44 @@ _wrap_nettle_pk_decrypt (gnutls_pk_algorithm_t algo, { int ret; + plaintext->data = NULL; + /* make a sexp from pkey */ switch (algo) { case GNUTLS_PK_RSA: { struct rsa_private_key priv; - bigint_t c, ri, nc; + struct rsa_public_key pub; + unsigned length; + bigint_t c; + + memset(&priv, 0, sizeof(priv)); + _rsa_params_to_privkey (pk_params, &priv); + _rsa_params_to_pubkey (pk_params, &pub); if (_gnutls_mpi_scan_nz (&c, ciphertext->data, ciphertext->size) != 0) { - gnutls_assert (); - return GNUTLS_E_MPI_SCAN_FAILED; + ret = gnutls_assert_val(GNUTLS_E_MPI_SCAN_FAILED); + goto cleanup; } - nc = rsa_blind (c, pk_params->params[1] /*e */ , - pk_params->params[0] /*m */ , &ri); - _gnutls_mpi_release (&c); - if (nc == NULL) + length = pub.size; + plaintext->data = gnutls_malloc(length); + if (plaintext->data == NULL) { - gnutls_assert (); - return GNUTLS_E_MEMORY_ERROR; + ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + goto cleanup; } + + ret = rsa_decrypt_tr(&pub, &priv, NULL, rnd_func, &length, plaintext->data, + TOMPZ(c)); + _gnutls_mpi_release (&c); + plaintext->size = length; - memset(&priv, 0, sizeof(priv)); - _rsa_params_to_privkey (pk_params, &priv); - - rsa_compute_root (&priv, TOMPZ (nc), TOMPZ (nc)); - - rsa_unblind (nc, ri, pk_params->params[0] /*m */ ); - - ret = _gnutls_mpi_dprint_size (nc, plaintext, ciphertext->size); - - _gnutls_mpi_release (&nc); - _gnutls_mpi_release (&ri); - - if (ret < 0) + if (ret == 0) { - gnutls_assert (); + ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); goto cleanup; } @@ -357,6 +304,8 @@ _wrap_nettle_pk_decrypt (gnutls_pk_algorithm_t algo, ret = 0; cleanup: + if (ret < 0) + gnutls_free(plaintext->data); return ret; } @@ -460,38 +409,25 @@ _wrap_nettle_pk_sign (gnutls_pk_algorithm_t algo, case GNUTLS_PK_RSA: { struct rsa_private_key priv; - bigint_t hash, nc, ri; - - if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0) - { - gnutls_assert (); - return GNUTLS_E_MPI_SCAN_FAILED; - } + mpz_t s; memset(&priv, 0, sizeof(priv)); _rsa_params_to_privkey (pk_params, &priv); - - nc = rsa_blind (hash, pk_params->params[1] /*e */ , - pk_params->params[0] /*m */ , &ri); - - _gnutls_mpi_release (&hash); - - if (nc == NULL) + + mpz_init(s); +// XXX change with _tr + ret = rsa_pkcs1_sign(&priv, vdata->size, vdata->data, s); + if (ret == 0) { - gnutls_assert (); - ret = GNUTLS_E_MEMORY_ERROR; + gnutls_assert(); + ret = GNUTLS_E_PK_SIGN_FAILED; goto rsa_fail; } - rsa_compute_root (&priv, TOMPZ (nc), TOMPZ (nc)); - - rsa_unblind (nc, ri, pk_params->params[0] /*m */ ); - - ret = _gnutls_mpi_dprint (nc, signature); + ret = _gnutls_mpi_dprint (s, signature); rsa_fail: - _gnutls_mpi_release (&nc); - _gnutls_mpi_release (&ri); + mpz_clear(s); if (ret < 0) { @@ -514,35 +450,6 @@ cleanup: return ret; } -static int -_int_rsa_verify (const gnutls_pk_params_st * pk_params, - bigint_t m, bigint_t s) -{ - int res; - - mpz_t m1; - - if ((mpz_sgn (TOMPZ (s)) <= 0) - || (mpz_cmp (TOMPZ (s), TOMPZ (pk_params->params[0])) >= 0)) - return GNUTLS_E_PK_SIG_VERIFY_FAILED; - - mpz_init (m1); - - mpz_powm (m1, TOMPZ (s), TOMPZ (pk_params->params[1]), - TOMPZ (pk_params->params[0])); - - res = !mpz_cmp (TOMPZ (m), m1); - - mpz_clear (m1); - - if (res == 0) - res = GNUTLS_E_PK_SIG_VERIFY_FAILED; - else - res = 0; - - return res; -} - static int _wrap_nettle_pk_verify (gnutls_pk_algorithm_t algo, const gnutls_datum_t * vdata, @@ -625,13 +532,9 @@ _wrap_nettle_pk_verify (gnutls_pk_algorithm_t algo, } case GNUTLS_PK_RSA: { - bigint_t hash; - - if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0) - { - gnutls_assert (); - return GNUTLS_E_MPI_SCAN_FAILED; - } + struct rsa_public_key pub; + + _rsa_params_to_pubkey (pk_params, &pub); ret = _gnutls_mpi_scan_nz (&tmp[0], signature->data, signature->size); if (ret < 0) @@ -640,9 +543,12 @@ _wrap_nettle_pk_verify (gnutls_pk_algorithm_t algo, goto cleanup; } - ret = _int_rsa_verify (pk_params, hash, tmp[0]); + ret = rsa_pkcs1_verify (&pub, vdata->size, vdata->data, TOMPZ(tmp[0])); + if (ret == 0) + ret = gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED); + else ret = 0; + _gnutls_mpi_release (&tmp[0]); - _gnutls_mpi_release (&hash); break; } default: @@ -1077,9 +983,91 @@ wrap_nettle_pk_fixup (gnutls_pk_algorithm_t algo, return 0; } +static int wrap_nettle_hash_algorithm (gnutls_pk_algorithm_t pk, + const gnutls_datum_t * sig, gnutls_pk_params_st * issuer_params, + gnutls_digest_algorithm_t* hash_algo) +{ + uint8_t digest[MAX_HASH_SIZE]; + uint8_t digest_info[MAX_HASH_SIZE*3]; + gnutls_datum_t di; + unsigned digest_size; + mpz_t s; + struct rsa_public_key pub; + int ret; + + mpz_init(s); + + switch (pk) + { + case GNUTLS_PK_DSA: + case GNUTLS_PK_EC: + + if (hash_algo) + *hash_algo = _gnutls_dsa_q_to_hash (pk, issuer_params, NULL); + + ret = 0; + break; + case GNUTLS_PK_RSA: + if (sig == NULL) + { /* return a sensible algorithm */ + if (hash_algo) + *hash_algo = GNUTLS_DIG_SHA256; + return 0; + } + + _rsa_params_to_pubkey (issuer_params, &pub); + + digest_size = sizeof(digest); + + nettle_mpz_set_str_256_u(s, sig->size, sig->data); + + digest_size = sizeof (digest_info); + ret = rsa_pkcs1_sign_extract_digest_info( &pub, &digest_size, digest_info, s); + if (ret == 0) + { + ret = GNUTLS_E_PK_SIG_VERIFY_FAILED; + gnutls_assert (); + goto cleanup; + } + + di.data = digest_info; + di.size = digest_size; + + digest_size = sizeof(digest); + if ((ret = + decode_ber_digest_info (&di, hash_algo, digest, + &digest_size)) < 0) + { + gnutls_assert (); + goto cleanup; + } + + if (digest_size != _gnutls_hash_get_algo_len (*hash_algo)) + { + gnutls_assert (); + ret = GNUTLS_E_PK_SIG_VERIFY_FAILED; + goto cleanup; + } + + ret = 0; + break; + + default: + gnutls_assert (); + ret = GNUTLS_E_INTERNAL_ERROR; + } + +cleanup: + mpz_clear(s); + return ret; + +} + + int crypto_pk_prio = INT_MAX; gnutls_crypto_pk_st _gnutls_pk_ops = { + .hash_algorithm = wrap_nettle_hash_algorithm, .encrypt = _wrap_nettle_pk_encrypt, .decrypt = _wrap_nettle_pk_decrypt, .sign = _wrap_nettle_pk_sign, diff --git a/lib/opencdk/main.h b/lib/opencdk/main.h index e786fe67c2..72bf7a9901 100644 --- a/lib/opencdk/main.h +++ b/lib/opencdk/main.h @@ -121,10 +121,6 @@ void _cdk_kbnode_add (cdk_kbnode_t root, cdk_kbnode_t node); void _cdk_kbnode_clone (cdk_kbnode_t node); /*-- sesskey.c --*/ -cdk_error_t _cdk_digest_encode_pkcs1 (byte ** r_md, size_t * r_mdlen, - int pk_algo, - const byte * md, - int digest_algo, unsigned nbits); cdk_error_t _cdk_sk_unprotect_auto (cdk_ctx_t hd, cdk_pkt_seckey_t sk); /*-- keydb.c --*/ diff --git a/lib/opencdk/pubkey.c b/lib/opencdk/pubkey.c index ab3d47cec0..492a0f2ef3 100644 --- a/lib/opencdk/pubkey.c +++ b/lib/opencdk/pubkey.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "opencdk.h" #include "main.h" @@ -72,13 +73,12 @@ sig_to_datum (gnutls_datum_t * r_sig, cdk_pkt_signature_t sig) cdk_error_t cdk_pk_verify (cdk_pubkey_t pk, cdk_pkt_signature_t sig, const byte * md) { - gnutls_datum_t s_sig; + gnutls_datum_t s_sig = { NULL, 0}, di = {NULL, 0}; byte *encmd = NULL; size_t enclen; cdk_error_t rc; int ret, algo; unsigned int i; - gnutls_datum_t data; gnutls_pk_params_st params; if (!pk || !sig || !md) @@ -104,22 +104,25 @@ cdk_pk_verify (cdk_pubkey_t pk, cdk_pkt_signature_t sig, const byte * md) goto leave; } - rc = _cdk_digest_encode_pkcs1 (&encmd, &enclen, pk->pubkey_algo, md, - sig->digest_algo, cdk_pk_get_nbits (pk)); - if (rc) + rc = _gnutls_set_datum (&di, md, _gnutls_hash_get_algo_len (sig->digest_algo)); + if (rc < 0) { - gnutls_assert (); + rc = gnutls_assert_val(CDK_Out_Of_Core); goto leave; - } + } - data.data = encmd; - data.size = enclen; + rc = pk_prepare_hash (algo, sig->digest_algo, &di); + if (rc < 0) + { + rc = gnutls_assert_val(CDK_General_Error); + goto leave; + } params.params_nr = cdk_pk_get_npkey (pk->pubkey_algo); for (i = 0; i < params.params_nr; i++) params.params[i] = pk->mpi[i]; params.flags = 0; - ret = _gnutls_pk_verify (algo, &data, &s_sig, ¶ms); + ret = _gnutls_pk_verify (algo, &di, &s_sig, ¶ms); if (ret < 0) { @@ -132,6 +135,7 @@ cdk_pk_verify (cdk_pubkey_t pk, cdk_pkt_signature_t sig, const byte * md) leave: _gnutls_free_datum (&s_sig); + _gnutls_free_datum (&di); cdk_free (encmd); return rc; } diff --git a/lib/opencdk/seskey.c b/lib/opencdk/seskey.c index 09863bf2b9..8d1d929211 100644 --- a/lib/opencdk/seskey.c +++ b/lib/opencdk/seskey.c @@ -29,170 +29,6 @@ #include "main.h" #include "packet.h" - -/* We encode the MD in this way: - * - * 0 1 PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) - * - * PAD consists of FF bytes. - */ -static cdk_error_t -do_encode_md (byte ** r_frame, size_t * r_flen, const byte * md, int algo, - size_t len, unsigned nbits, const byte * asn, size_t asnlen) -{ - byte *frame = NULL; - size_t nframe = (nbits + 7) / 8; - ssize_t i; - size_t n = 0; - - if (!asn || !md || !r_frame || !r_flen) - return CDK_Inv_Value; - - if (len + asnlen + 4 > nframe) - return CDK_General_Error; - - frame = cdk_calloc (1, nframe); - if (!frame) - return CDK_Out_Of_Core; - frame[n++] = 0; - frame[n++] = 1; - i = nframe - len - asnlen - 3; - if (i < 0) - { - cdk_free (frame); - return CDK_Inv_Value; - } - memset (frame + n, 0xFF, i); - n += i; - frame[n++] = 0; - memcpy (frame + n, asn, asnlen); - n += asnlen; - memcpy (frame + n, md, len); - n += len; - if (n != nframe) - { - cdk_free (frame); - return CDK_Inv_Value; - } - *r_frame = frame; - *r_flen = n; - return 0; -} - -static const byte md5_asn[18] = /* Object ID is 1.2.840.113549.2.5 */ -{ 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, - 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 -}; - -static const byte sha1_asn[15] = /* Object ID is 1.3.14.3.2.26 */ -{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, - 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 -}; - -static const byte sha224_asn[19] = /* Object ID is 2.16.840.1.101.3.4.2.4 */ -{ 0x30, 0x2D, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, - 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, - 0x1C -}; - -static const byte sha256_asn[19] = /* Object ID is 2.16.840.1.101.3.4.2.1 */ -{ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, - 0x00, 0x04, 0x20 -}; - -static const byte sha512_asn[] = /* Object ID is 2.16.840.1.101.3.4.2.3 */ -{ - 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, - 0x00, 0x04, 0x40 -}; - -static const byte sha384_asn[] = /* Object ID is 2.16.840.1.101.3.4.2.2 */ -{ - 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, - 0x00, 0x04, 0x30 -}; - -static const byte rmd160_asn[15] = /* Object ID is 1.3.36.3.2.1 */ -{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03, - 0x02, 0x01, 0x05, 0x00, 0x04, 0x14 -}; - -static int -_gnutls_get_digest_oid (gnutls_digest_algorithm_t algo, const byte ** data) -{ - switch (algo) - { - case GNUTLS_DIG_MD5: - *data = md5_asn; - return sizeof (md5_asn); - case GNUTLS_DIG_SHA1: - *data = sha1_asn; - return sizeof (sha1_asn); - case GNUTLS_DIG_RMD160: - *data = rmd160_asn; - return sizeof (rmd160_asn); - case GNUTLS_DIG_SHA256: - *data = sha256_asn; - return sizeof (sha256_asn); - case GNUTLS_DIG_SHA384: - *data = sha384_asn; - return sizeof (sha384_asn); - case GNUTLS_DIG_SHA512: - *data = sha512_asn; - return sizeof (sha512_asn); - case GNUTLS_DIG_SHA224: - *data = sha224_asn; - return sizeof (sha224_asn); - default: - gnutls_assert (); - return GNUTLS_E_INTERNAL_ERROR; - } -} - - -/* Encode the given digest into a pkcs#1 compatible format. */ -cdk_error_t -_cdk_digest_encode_pkcs1 (byte ** r_md, size_t * r_mdlen, int pk_algo, - const byte * md, int digest_algo, unsigned nbits) -{ - size_t dlen; - - if (!md || !r_md || !r_mdlen) - return CDK_Inv_Value; - - dlen = _gnutls_hash_get_algo_len (digest_algo); - if (dlen <= 0) - return CDK_Inv_Algo; - if (is_DSA (pk_algo)) - { /* DSS does not use a special encoding. */ - *r_md = cdk_malloc (dlen + 1); - if (!*r_md) - return CDK_Out_Of_Core; - *r_mdlen = dlen; - memcpy (*r_md, md, dlen); - return 0; - } - else - { - const byte *asn; - int asnlen; - cdk_error_t rc; - - asnlen = _gnutls_get_digest_oid (digest_algo, &asn); - if (asnlen < 0) - return asnlen; - - rc = do_encode_md (r_md, r_mdlen, md, digest_algo, dlen, - nbits, asn, asnlen); - return rc; - } - return 0; -} - - /** * cdk_s2k_new: * @ret_s2k: output for the new S2K object diff --git a/lib/openpgp/privkey.c b/lib/openpgp/privkey.c index 9be87b0206..8870ef6707 100644 --- a/lib/openpgp/privkey.c +++ b/lib/openpgp/privkey.c @@ -1281,7 +1281,7 @@ gnutls_openpgp_privkey_sign_hash (gnutls_openpgp_privkey_t key, result = - _gnutls_soft_sign (pk_algorithm, ¶ms, hash, signature); + _gnutls_pk_sign (pk_algorithm, signature, hash, ¶ms); gnutls_pk_params_release(¶ms); @@ -1351,22 +1351,12 @@ _gnutls_openpgp_privkey_decrypt_data (gnutls_openpgp_privkey_t key, return result; } - if (pk_algorithm != GNUTLS_PK_RSA) - { - gnutls_assert (); - return GNUTLS_E_INVALID_REQUEST; - } - - result = - _gnutls_pkcs1_rsa_decrypt (plaintext, ciphertext, ¶ms, 2); + result = _gnutls_pk_decrypt (pk_algorithm, plaintext, ciphertext, ¶ms); gnutls_pk_params_release(¶ms); if (result < 0) - { - gnutls_assert (); - return result; - } + return gnutls_assert_val(result); return 0; } diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c index 4d622ccb6e..5f9496b365 100644 --- a/lib/x509/privkey.c +++ b/lib/x509/privkey.c @@ -1476,8 +1476,7 @@ _gnutls_x509_privkey_sign_hash2 (gnutls_x509_privkey_t signer, goto cleanup; } - ret = _gnutls_soft_sign (signer->pk_algorithm, &signer->params, - &digest, signature); + ret = _gnutls_pk_sign (signer->pk_algorithm, signature, &digest, &signer->params); if (ret < 0) { @@ -1521,8 +1520,8 @@ gnutls_x509_privkey_sign_hash (gnutls_x509_privkey_t key, return GNUTLS_E_INVALID_REQUEST; } - result = _gnutls_soft_sign (key->pk_algorithm, &key->params, - hash, signature); + result = _gnutls_pk_sign (key->pk_algorithm, signature, hash, &key->params); + if (result < 0) { gnutls_assert (); diff --git a/lib/x509/verify.c b/lib/x509/verify.c index 4a133d451e..ee520e45e6 100644 --- a/lib/x509/verify.c +++ b/lib/x509/verify.c @@ -682,70 +682,7 @@ _gnutls_x509_verify_algorithm (gnutls_digest_algorithm_t * hash, gnutls_pk_algorithm_t pk, gnutls_pk_params_st * issuer_params) { - uint8_t digest[MAX_HASH_SIZE]; - gnutls_datum_t decrypted; - unsigned int digest_size; - int ret; - - switch (pk) - { - case GNUTLS_PK_DSA: - case GNUTLS_PK_EC: - - if (hash) - *hash = _gnutls_dsa_q_to_hash (pk, issuer_params, NULL); - - ret = 0; - break; - case GNUTLS_PK_RSA: - if (signature == NULL) - { /* return a sensible algorithm */ - if (hash) - *hash = GNUTLS_DIG_SHA256; - return 0; - } - - ret = - _gnutls_pkcs1_rsa_decrypt (&decrypted, signature, - issuer_params, 1); - - - if (ret < 0) - { - gnutls_assert (); - goto cleanup; - } - - digest_size = sizeof (digest); - if ((ret = - decode_ber_digest_info (&decrypted, hash, digest, - &digest_size)) != 0) - { - gnutls_assert (); - _gnutls_free_datum (&decrypted); - goto cleanup; - } - - _gnutls_free_datum (&decrypted); - if (digest_size != _gnutls_hash_get_algo_len (*hash)) - { - gnutls_assert (); - ret = GNUTLS_E_ASN1_GENERIC_ERROR; - goto cleanup; - } - - ret = 0; - break; - - default: - gnutls_assert (); - ret = GNUTLS_E_INTERNAL_ERROR; - } - -cleanup: - - return ret; - + return _gnutls_pk_hash_algorithm(pk, signature, issuer_params, hash); } /* verifies if the certificate is properly signed. @@ -788,39 +725,6 @@ _gnutls_x509_verify_data (gnutls_digest_algorithm_t algo, return ret; } -int -_gnutls_x509_verify_hashed_data (const gnutls_datum_t * hash, - const gnutls_datum_t * signature, - gnutls_x509_crt_t issuer) -{ - gnutls_pk_params_st issuer_params; - int ret; - - /* Read the MPI parameters from the issuer's certificate. - */ - ret = - _gnutls_x509_crt_get_mpis (issuer, &issuer_params); - if (ret < 0) - { - gnutls_assert (); - return ret; - } - - ret = - pubkey_verify_hashed_data (gnutls_x509_crt_get_pk_algorithm (issuer, NULL), - hash, signature, &issuer_params); - if (ret < 0) - { - gnutls_assert (); - } - - /* release all allocated MPIs - */ - gnutls_pk_params_release(&issuer_params); - - return ret; -} - /** * gnutls_x509_crt_list_verify: * @cert_list: is the certificate list to be verified diff --git a/lib/x509/x509.c b/lib/x509/x509.c index e69bab6369..c8b0cec0b0 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -2703,7 +2703,9 @@ gnutls_x509_crt_verify_hash (gnutls_x509_crt_t crt, unsigned int flags, const gnutls_datum_t * hash, const gnutls_datum_t * signature) { - int result; + gnutls_pk_params_st params; + gnutls_digest_algorithm_t algo; + int ret; if (crt == NULL) { @@ -2711,14 +2713,33 @@ gnutls_x509_crt_verify_hash (gnutls_x509_crt_t crt, unsigned int flags, return GNUTLS_E_INVALID_REQUEST; } - result = _gnutls_x509_verify_hashed_data (hash, signature, crt); - if (result < 0) + ret = gnutls_x509_crt_get_verify_algorithm (crt, signature, &algo); + if (ret < 0) + return gnutls_assert_val(ret); + + /* Read the MPI parameters from the issuer's certificate. + */ + ret = + _gnutls_x509_crt_get_mpis (crt, ¶ms); + if (ret < 0) { gnutls_assert (); - return result; + return ret; } - return result; + ret = + pubkey_verify_hashed_data (gnutls_x509_crt_get_pk_algorithm (crt, NULL), algo, + hash, signature, ¶ms); + if (ret < 0) + { + gnutls_assert (); + } + + /* release all allocated MPIs + */ + gnutls_pk_params_release(¶ms); + + return ret; } /** diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h index 19c2c1238b..3cc18e4bb0 100644 --- a/lib/x509/x509_int.h +++ b/lib/x509/x509_int.h @@ -151,10 +151,6 @@ int _gnutls_x509_verify_data (gnutls_digest_algorithm_t algo, const gnutls_datum_t * signature, gnutls_x509_crt_t issuer); -int _gnutls_x509_verify_hashed_data (const gnutls_datum_t * hash, - const gnutls_datum_t * signature, - gnutls_x509_crt_t issuer); - /* privkey.h */ ASN1_TYPE _gnutls_privkey_decode_pkcs1_rsa_key (const gnutls_datum_t * raw_key, diff --git a/tests/x509sign-verify.c b/tests/x509sign-verify.c index 9ac6b5d466..7e0727cf1f 100644 --- a/tests/x509sign-verify.c +++ b/tests/x509sign-verify.c @@ -40,6 +40,12 @@ #include "utils.h" +static void +tls_log_func (int level, const char *str) +{ + fprintf (stderr, "<%d> %s", level, str); +} + /* sha1 hash of "hello" string */ const gnutls_datum_t hash_data = { (void *) @@ -147,6 +153,7 @@ doit (void) gnutls_pubkey_t pubkey; gnutls_privkey_t privkey; gnutls_digest_algorithm_t hash_algo; + gnutls_sign_algorithm_t sign_algo; gnutls_datum_t signature; gnutls_datum_t signature2; int ret; @@ -154,6 +161,10 @@ doit (void) gnutls_global_init (); + gnutls_global_set_log_function (tls_log_func); + if (debug) + gnutls_global_set_log_level (6); + for (i = 0; i < sizeof (key_dat) / sizeof (key_dat[0]); i++) { if (debug) @@ -210,7 +221,7 @@ doit (void) ret = gnutls_pubkey_verify_hash (pubkey, 0, &hash_data, &signature); if (ret < 0) - fail ("gnutls_x509_privkey_verify_hash\n"); + fail ("gnutls_x509_pubkey_verify_hash\n"); ret = gnutls_pubkey_get_verify_algorithm (pubkey, &signature2, &hash_algo); @@ -219,12 +230,24 @@ doit (void) ret = gnutls_pubkey_verify_hash (pubkey, 0, &hash_data, &signature2); if (ret < 0) - fail ("gnutls_x509_privkey_verify_hash (hashed data)\n"); + fail ("gnutls_x509_pubkey_verify_hash-1 (hashed data)\n"); /* should fail */ ret = gnutls_pubkey_verify_hash (pubkey, 0, &invalid_hash_data, &signature2); if (ret != GNUTLS_E_PK_SIG_VERIFY_FAILED) - fail ("gnutls_x509_privkey_verify_hash (hashed data)\n"); + fail ("gnutls_x509_pubkey_verify_hash-2 (hashed data)\n"); + + sign_algo = gnutls_pk_to_sign(gnutls_pubkey_get_pk_algorithm(pubkey, NULL), + GNUTLS_DIG_SHA1); + + ret = gnutls_pubkey_verify_hash2 (pubkey, sign_algo, 0, &hash_data, &signature2); + if (ret < 0) + fail ("gnutls_x509_pubkey_verify_hash2-1 (hashed data)\n"); + + /* should fail */ + ret = gnutls_pubkey_verify_hash2 (pubkey, sign_algo, 0, &invalid_hash_data, &signature2); + if (ret != GNUTLS_E_PK_SIG_VERIFY_FAILED) + fail ("gnutls_x509_pubkey_verify_hash2-2 (hashed data)\n"); gnutls_free(signature.data);