diff options
Diffstat (limited to 'lib/x509/key_decode.c')
-rw-r--r-- | lib/x509/key_decode.c | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/lib/x509/key_decode.c b/lib/x509/key_decode.c index a1bf82688a..b1df8aaab3 100644 --- a/lib/x509/key_decode.c +++ b/lib/x509/key_decode.c @@ -39,6 +39,8 @@ static int _gnutls_x509_read_ecc_pubkey(uint8_t * der, int dersize, gnutls_pk_params_st * params); static int _gnutls_x509_read_eddsa_pubkey(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, @@ -117,6 +119,47 @@ int _gnutls_x509_read_eddsa_pubkey(uint8_t * der, int dersize, 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. @@ -387,6 +430,97 @@ _gnutls_x509_read_rsa_pss_params(uint8_t * der, int dersize, 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) +{ + int ret; + ASN1_TYPE spk = ASN1_TYPE_EMPTY; + char oid[MAX_OID_SIZE]; + int oid_size; + gnutls_ecc_curve_t curve; + int param; + + if ((ret = asn1_create_element(_gnutls_get_gnutls_asn(), + "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) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + /* For now ignore the OID: we use pk OID instead */ + + if (!strcmp(oid, HASH_OID_GOST_R_3411_94_CRYPTOPRO_PARAMS)) + param = GNUTLS_GOST_PARAMSET_CP_A; + else + param = GNUTLS_GOST_PARAMSET_TC26_Z; + + 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); + + if (param < 0) { + 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, @@ -423,6 +557,15 @@ int _gnutls_x509_read_pubkey(gnutls_pk_algorithm_t algo, uint8_t * der, case GNUTLS_PK_EDDSA_ED25519: ret = _gnutls_x509_read_eddsa_pubkey(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; @@ -446,6 +589,10 @@ int _gnutls_x509_read_pubkey_params(gnutls_pk_algorithm_t algo, 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); default: return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); } @@ -479,6 +626,9 @@ int _gnutls_x509_check_pubkey_params(gnutls_pk_params_st * params) case GNUTLS_PK_DSA: case GNUTLS_PK_ECDSA: case GNUTLS_PK_EDDSA_ED25519: + 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); |