/* * Copyright (C) 2017 Red Hat, Inc. * * 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 #include #include "errors.h" #include #include #include #include #include "prov-seed.h" /* This function encodes a seed value and a hash algorithm OID to the format * described in RFC8479. The output is the DER encoded form. */ int _x509_encode_provable_seed(gnutls_x509_privkey_t pkey, gnutls_datum_t *der) { ASN1_TYPE c2; int ret, result; const char *oid; oid = gnutls_digest_get_oid(pkey->params.palgo); if (oid == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); if ((result = asn1_create_element(_gnutls_get_gnutls_asn(), "GNUTLS.ProvableSeed", &c2)) != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } result = asn1_write_value(c2, "seed", pkey->params.seed, pkey->params.seed_size); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } result = asn1_write_value(c2, "algorithm", oid, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } ret = _gnutls_x509_der_encode(c2, "", der, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = 0; cleanup: asn1_delete_structure2(&c2, ASN1_DELETE_FLAG_ZEROIZE); return ret; } /* This function decodes a DER encoded form of seed and a hash algorithm, as in * RFC8479. */ int _x509_decode_provable_seed(gnutls_x509_privkey_t pkey, const gnutls_datum_t *der) { ASN1_TYPE c2; int ret, result; char oid[MAX_OID_SIZE]; int oid_size; gnutls_datum_t seed = {NULL, 0}; if ((result = asn1_create_element(_gnutls_get_gnutls_asn(), "GNUTLS.ProvableSeed", &c2)) != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } result = _asn1_strict_der_decode(&c2, der->data, der->size, NULL); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } ret = _gnutls_x509_read_value(c2, "seed", &seed); if (ret < 0) { gnutls_assert(); goto cleanup; } if (seed.size <= sizeof(pkey->params.seed)) { memcpy(pkey->params.seed, seed.data, seed.size); pkey->params.seed_size = seed.size; } else { ret = 0; /* ignore struct */ _gnutls_debug_log("%s: ignoring ProvableSeed due to very long params\n", __func__); goto cleanup; } oid_size = sizeof(oid); result = asn1_read_value(c2, "algorithm", oid, &oid_size); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } pkey->params.palgo = gnutls_oid_to_digest(oid); pkey->params.pkflags |= GNUTLS_PK_FLAG_PROVABLE; ret = 0; cleanup: gnutls_free(seed.data); asn1_delete_structure2(&c2, ASN1_DELETE_FLAG_ZEROIZE); return ret; }