From f0ade59b8c8c2f98968ac349cd7b180a08d894d9 Mon Sep 17 00:00:00 2001 From: Sona Sarmadi Date: Mon, 7 Sep 2015 11:26:11 +0200 Subject: gnutls: CVE-2015-0282 Fixes RSA PKCS#1 signature verification forgery References http://www.gnutls.org/security.html#GNUTLS-SA-2015-1 http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-0282 https://www.debian.org/security/2015/dsa-3191 Signed-off-by: Sona Sarmadi --- .../gnutls/CVE-2015-0282-GNUTLS-SA-2015-1.patch | 487 +++++++++++++++++++++ meta/recipes-support/gnutls/gnutls_2.12.23.bb | 1 + 2 files changed, 488 insertions(+) create mode 100644 meta/recipes-support/gnutls/gnutls/CVE-2015-0282-GNUTLS-SA-2015-1.patch diff --git a/meta/recipes-support/gnutls/gnutls/CVE-2015-0282-GNUTLS-SA-2015-1.patch b/meta/recipes-support/gnutls/gnutls/CVE-2015-0282-GNUTLS-SA-2015-1.patch new file mode 100644 index 0000000000..da84cbf57d --- /dev/null +++ b/meta/recipes-support/gnutls/gnutls/CVE-2015-0282-GNUTLS-SA-2015-1.patch @@ -0,0 +1,487 @@ +From d326f81daed5a1a06476d66a81584f8c7b71141d Mon Sep 17 00:00:00 2001 +From: Nikos Mavrogiannopoulos +Date: Mon, 23 Feb 2015 10:03:47 +0100 +Subject: [PATCH] Added fix for GNUTLS-SA-2015-1 + +Fixes CVE-2015-0282. +Upstream-Status: Backport + +Signed-off-by: Sona Sarmadi +--- + lib/gnutls_algorithms.c | 8 +++++ + lib/gnutls_algorithms.h | 1 + + lib/gnutls_pubkey.c | 4 +-- + lib/gnutls_sig.c | 14 +++++---- + lib/x509/common.h | 2 +- + lib/x509/crq.c | 49 ++++++++++++++++++++++++++++++- + lib/x509/privkey.c | 3 +- + lib/x509/verify.c | 77 ++++++++++++++++++++++++++++++++----------------- + lib/x509/x509.c | 4 +-- + lib/x509/x509_int.h | 7 +++-- + 10 files changed, 127 insertions(+), 42 deletions(-) + +diff --git a/lib/gnutls_algorithms.c b/lib/gnutls_algorithms.c +index 9ce73ce..b46f6f2 100644 +--- a/lib/gnutls_algorithms.c ++++ b/lib/gnutls_algorithms.c +@@ -2056,6 +2056,14 @@ gnutls_sign_get_name (gnutls_sign_algorithm_t algorithm) + return ret; + } + ++int ++_gnutls_sign_get_hash (gnutls_sign_algorithm_t algorithm) ++{ ++ GNUTLS_SIGN_LOOP (if (p->id == algorithm) return p->mac); ++ ++ return GNUTLS_MAC_UNKNOWN; ++} ++ + gnutls_sign_algorithm_t + _gnutls_x509_oid2sign_algorithm (const char *oid) + { +diff --git a/lib/gnutls_algorithms.h b/lib/gnutls_algorithms.h +index ac2ec71..8fa0fcb 100644 +--- a/lib/gnutls_algorithms.h ++++ b/lib/gnutls_algorithms.h +@@ -105,6 +105,7 @@ enum encipher_type + enum encipher_type _gnutls_kx_encipher_type (gnutls_kx_algorithm_t algorithm); + + /* Functions for sign algorithms. */ ++int _gnutls_sign_get_hash (gnutls_sign_algorithm_t algorithm); + 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_mac_algorithm_t mac); +diff --git a/lib/gnutls_pubkey.c b/lib/gnutls_pubkey.c +index dc4f545..8b50647 100644 +--- a/lib/gnutls_pubkey.c ++++ b/lib/gnutls_pubkey.c +@@ -1048,7 +1048,7 @@ gnutls_pubkey_verify_data (gnutls_pubkey_t pubkey, unsigned int flags, + return GNUTLS_E_INVALID_REQUEST; + } + +- ret = pubkey_verify_sig( data, NULL, signature, pubkey->pk_algorithm, ++ ret = pubkey_verify_sig(GNUTLS_MAC_UNKNOWN, data, NULL, signature, pubkey->pk_algorithm, + pubkey->params, pubkey->params_size); + if (ret < 0) + { +@@ -1086,7 +1086,7 @@ gnutls_pubkey_verify_hash (gnutls_pubkey_t key, unsigned int flags, + } + + ret = +- pubkey_verify_sig (NULL, hash, signature, key->pk_algorithm, ++ pubkey_verify_sig (GNUTLS_MAC_UNKNOWN, NULL, hash, signature, key->pk_algorithm, + key->params, key->params_size); + + return ret; +diff --git a/lib/gnutls_sig.c b/lib/gnutls_sig.c +index a2f38e5..9542925 100644 +--- a/lib/gnutls_sig.c ++++ b/lib/gnutls_sig.c +@@ -273,7 +273,8 @@ static int + verify_tls_hash (gnutls_session_t session, gnutls_protocol_t ver, gnutls_cert * cert, + const gnutls_datum_t * hash_concat, + gnutls_datum_t * signature, size_t sha1pos, +- gnutls_pk_algorithm_t pk_algo) ++ gnutls_pk_algorithm_t pk_algo, ++ int hashalg) + { + int ret; + gnutls_datum_t vdata; +@@ -309,7 +310,7 @@ verify_tls_hash (gnutls_session_t session, gnutls_protocol_t ver, gnutls_cert * + ret = _gnutls_rsa_verify (&vdata, signature, cert->params, + cert->params_size, 1); + else +- ret = pubkey_verify_sig( NULL, &vdata, signature, pk_algo, ++ ret = pubkey_verify_sig(hashalg, NULL, &vdata, signature, pk_algo, + cert->params, cert->params_size); + + if (ret < 0) +@@ -324,7 +325,7 @@ verify_tls_hash (gnutls_session_t session, gnutls_protocol_t ver, gnutls_cert * + vdata.data = &hash_concat->data[sha1pos]; + vdata.size = hash_concat->size - sha1pos; + +- ret = pubkey_verify_sig( NULL, &vdata, signature, pk_algo, ++ ret = pubkey_verify_sig(hashalg, NULL, &vdata, signature, pk_algo, + cert->params, cert->params_size); + /* verify signature */ + if (ret < 0) +@@ -428,7 +429,8 @@ _gnutls_handshake_verify_data (gnutls_session_t session, gnutls_cert * cert, + ret = verify_tls_hash (session, ver, cert, &dconcat, signature, + dconcat.size - + _gnutls_hash_get_algo_len (hash_algo), +- _gnutls_sign_get_pk_algorithm (algo)); ++ _gnutls_sign_get_pk_algorithm (algo), ++ hash_algo); + if (ret < 0) + { + gnutls_assert (); +@@ -491,7 +493,7 @@ _gnutls_handshake_verify_cert_vrfy12 (gnutls_session_t session, + + ret = + verify_tls_hash (session, ver, cert, &dconcat, signature, 0, +- cert->subject_pk_algorithm); ++ cert->subject_pk_algorithm, hash_algo); + if (ret < 0) + { + gnutls_assert (); +@@ -582,7 +584,7 @@ _gnutls_handshake_verify_cert_vrfy (gnutls_session_t session, + + ret = + verify_tls_hash (session, ver, cert, &dconcat, signature, 16, +- cert->subject_pk_algorithm); ++ cert->subject_pk_algorithm, GNUTLS_MAC_UNKNOWN); + if (ret < 0) + { + gnutls_assert (); +diff --git a/lib/x509/common.h b/lib/x509/common.h +index 5cc6a10..561e31c 100644 +--- a/lib/x509/common.h ++++ b/lib/x509/common.h +@@ -151,7 +151,7 @@ int _gnutls_get_key_id (gnutls_pk_algorithm_t pk, bigint_t * params, + void _asnstr_append_name (char *name, size_t name_size, const char *part1, + const char *part2); + +-int pubkey_verify_sig (const gnutls_datum_t * tbs, ++int pubkey_verify_sig (int hashalg, const gnutls_datum_t * tbs, + const gnutls_datum_t * hash, + const gnutls_datum_t * signature, + gnutls_pk_algorithm_t pk, bigint_t * issuer_params, +diff --git a/lib/x509/crq.c b/lib/x509/crq.c +index ed0f844..e0d3346 100644 +--- a/lib/x509/crq.c ++++ b/lib/x509/crq.c +@@ -2540,6 +2540,7 @@ gnutls_datum data = { NULL, 0 }; + gnutls_datum signature = { NULL, 0 }; + bigint_t params[MAX_PUBLIC_PARAMS_SIZE]; + int ret, params_size = 0, i; ++int hashalg, sigalg; + + ret = + _gnutls_x509_get_signed_data (crq->crq, "certificationRequestInfo", &data); +@@ -2565,7 +2566,10 @@ int ret, params_size = 0, i; + goto cleanup; + } + +- ret = pubkey_verify_sig(&data, NULL, &signature, ++ sigalg = gnutls_x509_crq_get_signature_algorithm (crq); ++ hashalg = _gnutls_sign_get_hash(sigalg); ++ ++ ret = pubkey_verify_sig(hashalg, &data, NULL, &signature, + gnutls_x509_crq_get_pk_algorithm (crq, NULL), + params, params_size); + if (ret < 0) +@@ -2588,5 +2592,48 @@ cleanup: + return ret; + } + ++/** ++ * gnutls_x509_crq_get_signature_algorithm: ++ * @crl: should contain a #gnutls_x509_crl_t structure ++ * ++ * This function will return a value of the #gnutls_sign_algorithm_t ++ * enumeration that is the signature algorithm. ++ * ++ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a ++ * negative error value. ++ **/ ++int ++gnutls_x509_crq_get_signature_algorithm (gnutls_x509_crq_t crq) ++{ ++ int result; ++ gnutls_datum_t sa; ++ ++ if (crq == NULL) ++ { ++ gnutls_assert (); ++ return GNUTLS_E_INVALID_REQUEST; ++ } ++ ++ /* Read the signature algorithm. Note that parameters are not ++ * read. They will be read from the issuer's certificate if needed. ++ */ ++ ++ result = ++ _gnutls_x509_read_value (crq->crq, "signatureAlgorithm.algorithm", ++ &sa, 0); ++ ++ if (result < 0) ++ { ++ gnutls_assert (); ++ return result; ++ } ++ ++ result = _gnutls_x509_oid2sign_algorithm ((const char *) sa.data); ++ ++ _gnutls_free_datum (&sa); ++ ++ return result; ++} ++ + #endif /* ENABLE_PKI */ + +diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c +index 41e6587..7f477a1 100644 +--- a/lib/x509/privkey.c ++++ b/lib/x509/privkey.c +@@ -1828,7 +1828,8 @@ gnutls_x509_privkey_verify_data (gnutls_x509_privkey_t key, + return GNUTLS_E_INVALID_REQUEST; + } + +- result = _gnutls_x509_privkey_verify_signature (data, signature, key); ++ result = _gnutls_x509_privkey_verify_signature (GNUTLS_MAC_UNKNOWN, data, signature, key); ++ + if (result < 0) + { + gnutls_assert (); +diff --git a/lib/x509/verify.c b/lib/x509/verify.c +index eef85a8..ba4fdcd 100644 +--- a/lib/x509/verify.c ++++ b/lib/x509/verify.c +@@ -332,6 +332,7 @@ _gnutls_verify_certificate2 (gnutls_x509_crt_t cert, + gnutls_datum_t cert_signature = { NULL, 0 }; + gnutls_x509_crt_t issuer = NULL; + int issuer_version, result = 0; ++ int sigalg, hashalg; + + if (output) + *output = 0; +@@ -399,8 +400,18 @@ _gnutls_verify_certificate2 (gnutls_x509_crt_t cert, + goto cleanup; + } + ++ sigalg = gnutls_x509_crt_get_signature_algorithm (cert); ++ hashalg = _gnutls_sign_get_hash(sigalg); ++ ++ if (hashalg == GNUTLS_MAC_UNKNOWN) ++ { ++ gnutls_assert(); ++ result = 0; ++ goto cleanup; ++ } ++ + result = +- _gnutls_x509_verify_signature (&cert_signed_data, NULL, &cert_signature, ++ _gnutls_x509_verify_signature (hashalg, &cert_signed_data, NULL, &cert_signature, + issuer); + if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED) + { +@@ -423,10 +434,6 @@ _gnutls_verify_certificate2 (gnutls_x509_crt_t cert, + */ + if (is_issuer (cert, cert) == 0) + { +- int sigalg; +- +- sigalg = gnutls_x509_crt_get_signature_algorithm (cert); +- + if (((sigalg == GNUTLS_SIGN_RSA_MD2) && + !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) || + ((sigalg == GNUTLS_SIGN_RSA_MD5) && +@@ -750,12 +757,12 @@ decode_ber_digest_info (const gnutls_datum_t * info, + * params[1] is public key + */ + static int +-_pkcs1_rsa_verify_sig (const gnutls_datum_t * text, +- const gnutls_datum_t * prehash, +- const gnutls_datum_t * signature, bigint_t * params, +- int params_len) ++_pkcs1_rsa_verify_sig (gnutls_mac_algorithm_t hash, const gnutls_datum_t * text, ++ const gnutls_datum_t * prehash, ++ const gnutls_datum_t * signature, bigint_t * params, ++ int params_len) + { +- gnutls_mac_algorithm_t hash = GNUTLS_MAC_UNKNOWN; ++ gnutls_mac_algorithm_t phash = GNUTLS_MAC_UNKNOWN; + int ret; + opaque digest[MAX_HASH_SIZE], md[MAX_HASH_SIZE], *cmp; + int digest_size; +@@ -775,7 +782,7 @@ _pkcs1_rsa_verify_sig (const gnutls_datum_t * text, + + digest_size = sizeof (digest); + if ((ret = +- decode_ber_digest_info (&decrypted, &hash, digest, &digest_size)) != 0) ++ decode_ber_digest_info (&decrypted, &phash, digest, &digest_size)) != 0) + { + gnutls_assert (); + _gnutls_free_datum (&decrypted); +@@ -784,6 +791,15 @@ _pkcs1_rsa_verify_sig (const gnutls_datum_t * text, + + _gnutls_free_datum (&decrypted); + ++ if (hash != GNUTLS_MAC_UNKNOWN && hash != phash) ++ { ++ gnutls_assert(); ++ return GNUTLS_E_PK_SIG_VERIFY_FAILED; ++ } ++ else ++ hash = phash; ++ ++ + if (digest_size != _gnutls_hash_get_algo_len (hash)) + { + gnutls_assert (); +@@ -879,11 +895,11 @@ dsa_verify_sig (const gnutls_datum_t * text, + * not verified, or 1 otherwise. + */ + int +-pubkey_verify_sig (const gnutls_datum_t * tbs, +- const gnutls_datum_t * hash, +- const gnutls_datum_t * signature, +- gnutls_pk_algorithm_t pk, bigint_t * issuer_params, +- int issuer_params_size) ++pubkey_verify_sig (int hashalg, const gnutls_datum_t * tbs, ++ const gnutls_datum_t * hash, ++ const gnutls_datum_t * signature, ++ gnutls_pk_algorithm_t pk, bigint_t * issuer_params, ++ int issuer_params_size) + { + + switch (pk) +@@ -891,7 +907,7 @@ pubkey_verify_sig (const gnutls_datum_t * tbs, + case GNUTLS_PK_RSA: + + if (_pkcs1_rsa_verify_sig +- (tbs, hash, signature, issuer_params, issuer_params_size) != 0) ++ (hashalg, tbs, hash, signature, issuer_params, issuer_params_size) != 0) + { + gnutls_assert (); + return GNUTLS_E_PK_SIG_VERIFY_FAILED; +@@ -1022,7 +1038,7 @@ cleanup: + * 'signature' is the signature! + */ + int +-_gnutls_x509_verify_signature (const gnutls_datum_t * tbs, ++_gnutls_x509_verify_signature (int hashalg, const gnutls_datum_t * tbs, + const gnutls_datum_t * hash, + const gnutls_datum_t * signature, + gnutls_x509_crt_t issuer) +@@ -1042,7 +1058,7 @@ _gnutls_x509_verify_signature (const gnutls_datum_t * tbs, + } + + ret = +- pubkey_verify_sig (tbs, hash, signature, ++ pubkey_verify_sig (hashalg, tbs, hash, signature, + gnutls_x509_crt_get_pk_algorithm (issuer, NULL), + issuer_params, issuer_params_size); + if (ret < 0) +@@ -1067,13 +1083,13 @@ _gnutls_x509_verify_signature (const gnutls_datum_t * tbs, + * 'signature' is the signature! + */ + int +-_gnutls_x509_privkey_verify_signature (const gnutls_datum_t * tbs, ++_gnutls_x509_privkey_verify_signature (int hashalg, const gnutls_datum_t * tbs, + const gnutls_datum_t * signature, + gnutls_x509_privkey_t issuer) + { + int ret; + +- ret = pubkey_verify_sig (tbs, NULL, signature, issuer->pk_algorithm, ++ ret = pubkey_verify_sig (hashalg, tbs, NULL, signature, issuer->pk_algorithm, + issuer->params, issuer->params_size); + if (ret < 0) + { +@@ -1294,6 +1310,7 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t crl, + gnutls_datum_t crl_signature = { NULL, 0 }; + gnutls_x509_crt_t issuer; + int result; ++ int sigalg, hashalg; + + if (output) + *output = 0; +@@ -1335,6 +1352,7 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t crl, + if (result < 0) + { + gnutls_assert (); ++ result = 0; + goto cleanup; + } + +@@ -1342,11 +1360,21 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t crl, + if (result < 0) + { + gnutls_assert (); ++ result = 0; ++ goto cleanup; ++ } ++ ++ sigalg = gnutls_x509_crl_get_signature_algorithm (crl); ++ hashalg = _gnutls_sign_get_hash(sigalg); ++ if (hashalg == GNUTLS_MAC_UNKNOWN) ++ { ++ gnutls_assert(); ++ result = 0; + goto cleanup; + } + + result = +- _gnutls_x509_verify_signature (&crl_signed_data, NULL, &crl_signature, ++ _gnutls_x509_verify_signature (hashalg, &crl_signed_data, NULL, &crl_signature, + issuer); + if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED) + { +@@ -1359,14 +1387,11 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t crl, + else if (result < 0) + { + gnutls_assert (); ++ result = 0; + goto cleanup; + } + + { +- int sigalg; +- +- sigalg = gnutls_x509_crl_get_signature_algorithm (crl); +- + if (((sigalg == GNUTLS_SIGN_RSA_MD2) && + !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) || + ((sigalg == GNUTLS_SIGN_RSA_MD5) && +diff --git a/lib/x509/x509.c b/lib/x509/x509.c +index f51ba3b..d12d44e 100644 +--- a/lib/x509/x509.c ++++ b/lib/x509/x509.c +@@ -2714,7 +2714,7 @@ gnutls_x509_crt_verify_data (gnutls_x509_crt_t crt, unsigned int flags, + return GNUTLS_E_INVALID_REQUEST; + } + +- result = _gnutls_x509_verify_signature (data, NULL, signature, crt); ++ result = _gnutls_x509_verify_signature (GNUTLS_MAC_UNKNOWN, data, NULL, signature, crt); + if (result < 0) + { + gnutls_assert (); +@@ -2752,7 +2752,7 @@ gnutls_x509_crt_verify_hash (gnutls_x509_crt_t crt, unsigned int flags, + return GNUTLS_E_INVALID_REQUEST; + } + +- result = _gnutls_x509_verify_signature (NULL, hash, signature, crt); ++ result = _gnutls_x509_verify_signature (GNUTLS_MAC_UNKNOWN, NULL, hash, signature, crt); + if (result < 0) + { + gnutls_assert (); +diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h +index 1b3cfe5..eed56a9 100644 +--- a/lib/x509/x509_int.h ++++ b/lib/x509/x509_int.h +@@ -187,11 +187,11 @@ _gnutls_x509_verify_algorithm (gnutls_mac_algorithm_t * hash, + bigint_t * issuer_params, + unsigned int issuer_params_size); + +-int _gnutls_x509_verify_signature (const gnutls_datum_t * tbs, ++int _gnutls_x509_verify_signature (int sigalg, const gnutls_datum_t * tbs, + const gnutls_datum_t * hash, + const gnutls_datum_t * signature, + gnutls_x509_crt_t issuer); +-int _gnutls_x509_privkey_verify_signature (const gnutls_datum_t * tbs, ++int _gnutls_x509_privkey_verify_signature (int sigalg, const gnutls_datum_t * tbs, + const gnutls_datum_t * signature, + gnutls_x509_privkey_t issuer); + +@@ -390,5 +390,6 @@ int _gnutls_x509_crq_set_extension (gnutls_x509_crq_t crq, + const char *ext_id, + const gnutls_datum_t * ext_data, + unsigned int critical); +- ++int ++gnutls_x509_crq_get_signature_algorithm (gnutls_x509_crq_t crq); + #endif +-- +1.9.1 + diff --git a/meta/recipes-support/gnutls/gnutls_2.12.23.bb b/meta/recipes-support/gnutls/gnutls_2.12.23.bb index efe9e04ee1..dc31b436dd 100644 --- a/meta/recipes-support/gnutls/gnutls_2.12.23.bb +++ b/meta/recipes-support/gnutls/gnutls_2.12.23.bb @@ -9,6 +9,7 @@ SRC_URI += "file://gnutls-openssl.patch \ file://CVE-2014-1959-rejection-of-v1-intermediate-cert.patch \ file://CVE-2014-0092-corrected-return-codes.patch \ file://CVE-2014-3466.patch \ + file://CVE-2015-0282-GNUTLS-SA-2015-1.patch \ file://25_updatedgdocfrommaster.diff \ ${@['', 'file://fix-gettext-version.patch'][bb.data.inherits_class('native', d) or (not ((d.getVar("INCOMPATIBLE_LICENSE", True) or "").find("GPLv3") != -1))]} \ " -- cgit v1.2.3-54-g00ecf