/* * Copyright (C) 2011-2012 Free Software Foundation, Inc. * Copyright (C) 2013-2017 Red Hat * * Author: Nikos Mavrogiannopoulos * * This file is part of GnuTLS. * * The GnuTLS is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see * */ #include "gnutls_int.h" #include "errors.h" #include #include #include #include "common.h" #include "x509_int.h" #include "pk.h" #include #include static int _gnutls_x509_read_rsa_pubkey(uint8_t * der, int dersize, gnutls_pk_params_st * params); static int _gnutls_x509_read_dsa_pubkey(uint8_t * der, int dersize, gnutls_pk_params_st * params); static int _gnutls_x509_read_ecc_pubkey(uint8_t * der, int dersize, gnutls_pk_params_st * params); static int _gnutls_x509_read_eddsa_pubkey(gnutls_ecc_curve_t curve, uint8_t * der, int dersize, gnutls_pk_params_st * params); static int _gnutls_x509_read_gost_pubkey(uint8_t * der, int dersize, gnutls_pk_params_st * params); static int _gnutls_x509_read_dsa_params(uint8_t * der, int dersize, gnutls_pk_params_st * params); /* * some x509 certificate parsing functions that relate to MPI parameter * extraction. This reads the BIT STRING subjectPublicKey. * Returns 2 parameters (m,e). It does not set params_nr. */ int _gnutls_x509_read_rsa_pubkey(uint8_t * der, int dersize, gnutls_pk_params_st * params) { int result; ASN1_TYPE spk = ASN1_TYPE_EMPTY; if ((result = asn1_create_element (_gnutls_get_gnutls_asn(), "GNUTLS.RSAPublicKey", &spk)) != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } result = asn1_der_decoding(&spk, der, dersize, NULL); if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&spk); return _gnutls_asn2err(result); } if (_gnutls_x509_read_int(spk, "modulus", ¶ms->params[0]) < 0) { gnutls_assert(); asn1_delete_structure(&spk); return GNUTLS_E_ASN1_GENERIC_ERROR; } if (_gnutls_x509_read_int(spk, "publicExponent", ¶ms->params[1]) < 0) { gnutls_assert(); _gnutls_mpi_release(¶ms->params[0]); asn1_delete_structure(&spk); return GNUTLS_E_ASN1_GENERIC_ERROR; } asn1_delete_structure(&spk); return 0; } /* * some x509 certificate parsing functions that relate to MPI parameter * extraction. This reads the BIT STRING subjectPublicKey. * Returns 2 parameters (m,e). It does not set params_nr. */ int _gnutls_x509_read_ecc_pubkey(uint8_t * der, int dersize, gnutls_pk_params_st * params) { /* RFC5480 defines the public key to be an ECPoint (i.e. OCTET STRING), * Then it says that the OCTET STRING _value_ is converted to BIT STRING. * That means that the value we place there is the raw X9.62 one. */ return _gnutls_ecc_ansi_x962_import(der, dersize, ¶ms->params[ECC_X], ¶ms->params[ECC_Y]); } int _gnutls_x509_read_eddsa_pubkey(gnutls_ecc_curve_t curve, uint8_t * der, int dersize, gnutls_pk_params_st * params) { int size = gnutls_ecc_curve_get_size(curve); if (dersize != size) return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); return _gnutls_set_datum(¶ms->raw_pub, der, dersize); } /* Pubkey is a concatenation of X (in little endian) and Y (also LE) * encoded into OCTET STRING. */ static int _gnutls_x509_read_gost_pubkey(uint8_t * der, int dersize, gnutls_pk_params_st * params) { int ret; int len; bigint_t *x = ¶ms->params[GOST_X]; bigint_t *y = ¶ms->params[GOST_Y]; /* Quick and dirty parsing of OCTET STRING of 0x40 or 0x80 bytes */ if (dersize < 1 || der[0] != ASN1_TAG_OCTET_STRING) { return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); } der++; dersize--; ret = asn1_get_length_der(der, dersize, &len); if (ret <= 0 || ret % 2 != 0 || dersize != len + ret) { return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); } der += len; dersize -= len; /* read data */ ret = _gnutls_mpi_init_scan_le(x, der, dersize / 2); if (ret < 0) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); ret = _gnutls_mpi_init_scan_le(y, der + dersize / 2, dersize / 2); if (ret < 0) { _gnutls_mpi_release(y); return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); } return 0; } /* reads p,q and g * from the certificate (subjectPublicKey BIT STRING). * params[0-2]. It does NOT set params_nr. */ static int _gnutls_x509_read_dsa_params(uint8_t * der, int dersize, gnutls_pk_params_st * params) { int result; ASN1_TYPE spk = ASN1_TYPE_EMPTY; if ((result = asn1_create_element (_gnutls_get_pkix(), "PKIX1.Dss-Parms", &spk)) != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } result = asn1_der_decoding(&spk, der, dersize, NULL); if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&spk); return _gnutls_asn2err(result); } /* If the parameters are not included in the certificate * then the issuer's parameters should be used. This is not * implemented, and is not used in practice (along with DSA). */ /* Read p */ if (_gnutls_x509_read_int(spk, "p", ¶ms->params[0]) < 0) { gnutls_assert(); asn1_delete_structure(&spk); return GNUTLS_E_ASN1_GENERIC_ERROR; } /* Read q */ if (_gnutls_x509_read_int(spk, "q", ¶ms->params[1]) < 0) { gnutls_assert(); asn1_delete_structure(&spk); _gnutls_mpi_release(¶ms->params[0]); return GNUTLS_E_ASN1_GENERIC_ERROR; } /* Read g */ if (_gnutls_x509_read_int(spk, "g", ¶ms->params[2]) < 0) { gnutls_assert(); asn1_delete_structure(&spk); _gnutls_mpi_release(¶ms->params[0]); _gnutls_mpi_release(¶ms->params[1]); return GNUTLS_E_ASN1_GENERIC_ERROR; } asn1_delete_structure(&spk); params->params_nr = 3; /* public key is missing */ params->algo = GNUTLS_PK_DSA; return 0; } /* reads the curve from the certificate. * params[0-4]. It does NOT set params_nr. */ int _gnutls_x509_read_ecc_params(uint8_t * der, int dersize, unsigned int * curve) { int ret; ASN1_TYPE spk = ASN1_TYPE_EMPTY; char oid[MAX_OID_SIZE]; int oid_size; if ((ret = asn1_create_element (_gnutls_get_gnutls_asn(), "GNUTLS.ECParameters", &spk)) != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(ret); } ret = asn1_der_decoding(&spk, der, dersize, NULL); if (ret != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(ret); goto cleanup; } /* read the curve */ oid_size = sizeof(oid); ret = asn1_read_value(spk, "namedCurve", oid, &oid_size); if (ret != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(ret); goto cleanup; } *curve = gnutls_oid_to_ecc_curve(oid); if (*curve == GNUTLS_ECC_CURVE_INVALID) { _gnutls_debug_log("Curve %s is not supported\n", oid); gnutls_assert(); ret = GNUTLS_E_ECC_UNSUPPORTED_CURVE; goto cleanup; } ret = 0; cleanup: asn1_delete_structure(&spk); return ret; } /* Reads RSA-PSS parameters. */ int _gnutls_x509_read_rsa_pss_params(uint8_t * der, int dersize, gnutls_x509_spki_st * params) { int result; ASN1_TYPE spk = ASN1_TYPE_EMPTY; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; gnutls_digest_algorithm_t digest; char oid[MAX_OID_SIZE] = ""; int size; unsigned int trailer; gnutls_datum_t value = { NULL, 0 }; if ((result = asn1_create_element (_gnutls_get_gnutls_asn(), "GNUTLS.RSAPSSParameters", &spk)) != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } result = _asn1_strict_der_decode(&spk, der, dersize, NULL); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } size = sizeof(oid); result = asn1_read_value(spk, "hashAlgorithm.algorithm", oid, &size); if (result == ASN1_SUCCESS) digest = gnutls_oid_to_digest(oid); else if (result == ASN1_ELEMENT_NOT_FOUND) /* The default hash algorithm is SHA-1 */ digest = GNUTLS_DIG_SHA1; else { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } if (digest == GNUTLS_DIG_UNKNOWN) { gnutls_assert(); _gnutls_debug_log("Unknown RSA-PSS hash: %s\n", oid); result = GNUTLS_E_UNKNOWN_HASH_ALGORITHM; goto cleanup; } size = sizeof(oid); result = asn1_read_value(spk, "maskGenAlgorithm.algorithm", oid, &size); if (result == ASN1_SUCCESS) { gnutls_digest_algorithm_t digest2; /* Error out if algorithm other than mgf1 is specified */ if (strcmp(oid, PKIX1_RSA_PSS_MGF1_OID) != 0) { gnutls_assert(); _gnutls_debug_log("Unknown mask algorithm: %s\n", oid); result = GNUTLS_E_UNKNOWN_ALGORITHM; goto cleanup; } /* Check if maskGenAlgorithm.parameters does exist and * is identical to hashAlgorithm */ result = _gnutls_x509_read_value(spk, "maskGenAlgorithm.parameters", &value); if (result < 0) { gnutls_assert(); goto cleanup; } if ((result = asn1_create_element (_gnutls_get_pkix(), "PKIX1.AlgorithmIdentifier", &c2)) != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } result = _asn1_strict_der_decode(&c2, value.data, value.size, NULL); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } size = sizeof(oid); result = asn1_read_value(c2, "algorithm", oid, &size); if (result == ASN1_SUCCESS) digest2 = gnutls_oid_to_digest(oid); else if (result == ASN1_ELEMENT_NOT_FOUND) /* The default hash algorithm for mgf1 is SHA-1 */ digest2 = GNUTLS_DIG_SHA1; else { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } if (digest != digest2) { gnutls_assert(); result = GNUTLS_E_CONSTRAINT_ERROR; goto cleanup; } } else if (result != ASN1_ELEMENT_NOT_FOUND) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } memset(params, 0, sizeof(gnutls_x509_spki_st)); params->pk = GNUTLS_PK_RSA_PSS; params->rsa_pss_dig = digest; result = _gnutls_x509_read_uint(spk, "saltLength", ¶ms->salt_size); if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND || result == GNUTLS_E_ASN1_VALUE_NOT_FOUND) params->salt_size = 20; else if (result < 0) { gnutls_assert(); goto cleanup; } result = _gnutls_x509_read_uint(spk, "trailerField", &trailer); if (result == GNUTLS_E_ASN1_VALUE_NOT_FOUND || result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) trailer = 1; else if (result < 0) { gnutls_assert(); goto cleanup; } if (trailer != 1) { gnutls_assert(); result = GNUTLS_E_CERTIFICATE_ERROR; goto cleanup; } result = 0; cleanup: _gnutls_free_datum(&value); asn1_delete_structure(&c2); asn1_delete_structure(&spk); return result; } /* reads the curve from the certificate. * It does NOT set params_nr. */ int _gnutls_x509_read_gost_params(uint8_t * der, int dersize, gnutls_pk_params_st * params, gnutls_pk_algorithm_t algo) { int ret; ASN1_TYPE spk = ASN1_TYPE_EMPTY; char oid[MAX_OID_SIZE]; int oid_size; gnutls_ecc_curve_t curve; gnutls_gost_paramset_t param; if ((ret = asn1_create_element(_gnutls_get_gnutls_asn(), algo == GNUTLS_PK_GOST_01 ? "GNUTLS.GOSTParametersOld" : "GNUTLS.GOSTParameters", &spk)) != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(ret); } ret = _asn1_strict_der_decode(&spk, der, dersize, NULL); if (ret != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(ret); goto cleanup; } /* read the curve */ oid_size = sizeof(oid); ret = asn1_read_value(spk, "publicKeyParamSet", oid, &oid_size); if (ret != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(ret); goto cleanup; } curve = gnutls_oid_to_ecc_curve(oid); if (curve == GNUTLS_ECC_CURVE_INVALID) { _gnutls_debug_log("Curve %s is not supported\n", oid); gnutls_assert(); ret = GNUTLS_E_ECC_UNSUPPORTED_CURVE; goto cleanup; } /* Read the digest */ oid_size = sizeof(oid); ret = asn1_read_value(spk, "digestParamSet", oid, &oid_size); if (ret != ASN1_SUCCESS && ret != ASN1_ELEMENT_NOT_FOUND) { gnutls_assert(); ret = _gnutls_asn2err(ret); goto cleanup; } /* For now ignore the OID: we use pk OID instead */ oid_size = sizeof(oid); ret = asn1_read_value(spk, "encryptionParamSet", oid, &oid_size); if (ret != ASN1_SUCCESS && ret != ASN1_ELEMENT_NOT_FOUND) { gnutls_assert(); ret = _gnutls_asn2err(ret); goto cleanup; } if (ret != ASN1_ELEMENT_NOT_FOUND) param = gnutls_oid_to_gost_paramset(oid); else param = _gnutls_gost_paramset_default(algo); if (param == GNUTLS_GOST_PARAMSET_UNKNOWN) { gnutls_assert(); ret = param; goto cleanup; } params->curve = curve; params->gost_params = param; ret = 0; cleanup: asn1_delete_structure(&spk); return ret; } /* This function must be called after _gnutls_x509_read_params() */ int _gnutls_x509_read_pubkey(gnutls_pk_algorithm_t algo, uint8_t * der, int dersize, gnutls_pk_params_st * params) { int ret; switch (algo) { case GNUTLS_PK_RSA: case GNUTLS_PK_RSA_PSS: ret = _gnutls_x509_read_rsa_pubkey(der, dersize, params); if (ret >= 0) { params->algo = algo; params->params_nr = RSA_PUBLIC_PARAMS; } break; case GNUTLS_PK_DSA: if (params->params_nr != 3) /* _gnutls_x509_read_pubkey_params must have been called */ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ret = _gnutls_x509_read_dsa_pubkey(der, dersize, params); if (ret >= 0) { params->algo = GNUTLS_PK_DSA; params->params_nr = DSA_PUBLIC_PARAMS; } break; case GNUTLS_PK_ECDSA: ret = _gnutls_x509_read_ecc_pubkey(der, dersize, params); if (ret >= 0) { params->algo = GNUTLS_PK_ECDSA; params->params_nr = ECC_PUBLIC_PARAMS; } break; case GNUTLS_PK_EDDSA_ED25519: ret = _gnutls_x509_read_eddsa_pubkey(GNUTLS_ECC_CURVE_ED25519, der, dersize, params); break; case GNUTLS_PK_EDDSA_ED448: ret = _gnutls_x509_read_eddsa_pubkey(GNUTLS_ECC_CURVE_ED448, der, dersize, params); break; case GNUTLS_PK_GOST_01: case GNUTLS_PK_GOST_12_256: case GNUTLS_PK_GOST_12_512: ret = _gnutls_x509_read_gost_pubkey(der, dersize, params); if (ret >= 0) { params->algo = algo; params->params_nr = GOST_PUBLIC_PARAMS; } break; default: ret = gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); break; } return ret; } /* This function must be called prior to _gnutls_x509_read_pubkey() */ int _gnutls_x509_read_pubkey_params(gnutls_pk_algorithm_t algo, uint8_t * der, int dersize, gnutls_pk_params_st * params) { switch (algo) { case GNUTLS_PK_RSA: case GNUTLS_PK_EDDSA_ED25519: case GNUTLS_PK_EDDSA_ED448: return 0; case GNUTLS_PK_RSA_PSS: return _gnutls_x509_read_rsa_pss_params(der, dersize, ¶ms->spki); case GNUTLS_PK_DSA: return _gnutls_x509_read_dsa_params(der, dersize, params); case GNUTLS_PK_EC: return _gnutls_x509_read_ecc_params(der, dersize, ¶ms->curve); case GNUTLS_PK_GOST_01: case GNUTLS_PK_GOST_12_256: case GNUTLS_PK_GOST_12_512: return _gnutls_x509_read_gost_params(der, dersize, params, algo); default: return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); } } /* This function must be called after _gnutls_x509_read_pubkey() */ int _gnutls_x509_check_pubkey_params(gnutls_pk_params_st * params) { switch (params->algo) { case GNUTLS_PK_RSA_PSS: { unsigned bits; const mac_entry_st *me; size_t hash_size; if (params->spki.pk == GNUTLS_PK_UNKNOWN) /* no params present */ return 0; bits = pubkey_to_bits(params); me = hash_to_entry(params->spki.rsa_pss_dig); if (unlikely(me == NULL)) return gnutls_assert_val(GNUTLS_E_PK_INVALID_PUBKEY_PARAMS); hash_size = _gnutls_hash_get_algo_len(me); if (hash_size + params->spki.salt_size + 2 > (bits + 7) / 8) return gnutls_assert_val(GNUTLS_E_PK_INVALID_PUBKEY_PARAMS); return 0; } case GNUTLS_PK_RSA: case GNUTLS_PK_DSA: case GNUTLS_PK_ECDSA: case GNUTLS_PK_EDDSA_ED25519: case GNUTLS_PK_EDDSA_ED448: case GNUTLS_PK_GOST_01: case GNUTLS_PK_GOST_12_256: case GNUTLS_PK_GOST_12_512: return 0; default: return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); } } /* reads DSA's Y * from the certificate * only sets params[3] */ int _gnutls_x509_read_dsa_pubkey(uint8_t * der, int dersize, gnutls_pk_params_st * params) { return _gnutls_x509_read_der_int(der, dersize, ¶ms->params[3]); }