/* * Copyright (C) 2001-2012 Free Software Foundation, 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 3 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int sign_tls_hash (gnutls_session_t session, gnutls_digest_algorithm_t hash_algo, gnutls_pcert_st* cert, gnutls_privkey_t pkey, 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 * other RSA signatures including one with the old MD5/SHA1-combined * format. */ #define MAX_SIG_SIZE 19 + MAX_HASH_SIZE /* Generates a signature of all the random data and the parameters. * Used in DHE_* ciphersuites. */ int _gnutls_handshake_sign_data (gnutls_session_t session, gnutls_pcert_st* cert, gnutls_privkey_t pkey, gnutls_datum_t * params, gnutls_datum_t * signature, gnutls_sign_algorithm_t * sign_algo) { gnutls_datum_t dconcat; int ret; digest_hd_st td_sha; uint8_t concat[MAX_SIG_SIZE]; gnutls_protocol_t ver = gnutls_protocol_get_version (session); gnutls_digest_algorithm_t hash_algo; *sign_algo = _gnutls_session_get_sign_algo (session, cert); if (*sign_algo == GNUTLS_SIGN_UNKNOWN) { gnutls_assert (); return GNUTLS_E_UNKNOWN_PK_ALGORITHM; } hash_algo = _gnutls_sign_get_hash_algorithm (*sign_algo); _gnutls_handshake_log ("HSK[%p]: signing handshake data: using %s\n", session, gnutls_sign_algorithm_get_name (*sign_algo)); ret = _gnutls_hash_init (&td_sha, hash_algo); if (ret < 0) { gnutls_assert (); return ret; } _gnutls_hash (&td_sha, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); _gnutls_hash (&td_sha, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); _gnutls_hash (&td_sha, params->data, params->size); switch (gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL)) { case GNUTLS_PK_RSA: if (!_gnutls_version_has_selectable_sighash (ver)) { digest_hd_st td_md5; ret = _gnutls_hash_init (&td_md5, GNUTLS_MAC_MD5); if (ret < 0) { gnutls_assert (); return ret; } _gnutls_hash (&td_md5, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); _gnutls_hash (&td_md5, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); _gnutls_hash (&td_md5, params->data, params->size); _gnutls_hash_deinit (&td_md5, concat); _gnutls_hash_deinit (&td_sha, &concat[16]); dconcat.data = concat; dconcat.size = 36; } else { /* TLS 1.2 way */ _gnutls_hash_deinit (&td_sha, concat); dconcat.data = concat; dconcat.size = _gnutls_hash_get_algo_len (hash_algo); } break; case GNUTLS_PK_DSA: case GNUTLS_PK_EC: _gnutls_hash_deinit (&td_sha, concat); if (!IS_SHA(hash_algo)) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } dconcat.data = concat; dconcat.size = _gnutls_hash_get_algo_len (hash_algo); break; default: gnutls_assert (); _gnutls_hash_deinit (&td_sha, NULL); return GNUTLS_E_INTERNAL_ERROR; } ret = sign_tls_hash (session, hash_algo, cert, pkey, &dconcat, signature); if (ret < 0) { gnutls_assert (); } return ret; } /* 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. */ static int sign_tls_hash (gnutls_session_t session, gnutls_digest_algorithm_t hash_algo, gnutls_pcert_st* cert, gnutls_privkey_t pkey, const gnutls_datum_t * hash_concat, gnutls_datum_t * signature) { gnutls_protocol_t ver = gnutls_protocol_get_version (session); unsigned int key_usage = 0; /* If our certificate supports signing */ if (cert != NULL) { gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage); if (key_usage != 0) if (!(key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { gnutls_assert (); _gnutls_audit_log(session, "Peer's certificate does not allow digital signatures. Key usage violation detected (ignored).\n"); } /* External signing. Deprecated. To be removed. */ if (!pkey) { int ret; if (!session->internals.sign_func) return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); if (!_gnutls_version_has_selectable_sighash (ver)) return (*session->internals.sign_func) (session, session->internals.sign_func_userdata, cert->type, &cert->cert, hash_concat, signature); else { gnutls_datum_t digest; ret = _gnutls_set_datum(&digest, hash_concat->data, hash_concat->size); if (ret < 0) return gnutls_assert_val(ret); ret = pk_prepare_hash (gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL), hash_algo, &digest); if (ret < 0) { gnutls_assert (); goto es_cleanup; } ret = (*session->internals.sign_func) (session, session->internals.sign_func_userdata, cert->type, &cert->cert, &digest, signature); es_cleanup: gnutls_free(digest.data); return ret; } } } if (!_gnutls_version_has_selectable_sighash (ver)) return _gnutls_privkey_sign_hash (pkey, hash_concat, signature); else return gnutls_privkey_sign_hash (pkey, hash_algo, 0, hash_concat, signature); } static int verify_tls_hash (gnutls_session_t session, gnutls_protocol_t ver, gnutls_pcert_st* cert, 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; unsigned int key_usage = 0, flags; if (cert == NULL) { gnutls_assert (); return GNUTLS_E_CERTIFICATE_ERROR; } gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage); /* If the certificate supports signing continue. */ if (key_usage != 0) if (!(key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { gnutls_assert (); _gnutls_audit_log(session, "Peer's certificate does not allow digital signatures. Key usage violation detected (ignored).\n"); } if (pk_algo == GNUTLS_PK_UNKNOWN) pk_algo = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL); switch (pk_algo) { case GNUTLS_PK_RSA: vdata.data = hash_concat->data; vdata.size = hash_concat->size; /* verify signature */ if (!_gnutls_version_has_selectable_sighash (ver)) 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; flags = 0; break; default: gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } ret = gnutls_pubkey_verify_hash2(cert->pubkey, sign_algo, flags, &vdata, signature); if (ret < 0) return gnutls_assert_val(ret); return 0; } /* Generates a signature of all the random data and the parameters. * Used in DHE_* ciphersuites. */ 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 sign_algo) { gnutls_datum_t dconcat; int ret; digest_hd_st td_md5; digest_hd_st td_sha; uint8_t concat[MAX_SIG_SIZE]; gnutls_protocol_t ver = gnutls_protocol_get_version (session); gnutls_digest_algorithm_t hash_algo; if (_gnutls_version_has_selectable_sighash (ver)) { _gnutls_handshake_log ("HSK[%p]: verify handshake data: using %s\n", session, gnutls_sign_algorithm_get_name (sign_algo)); ret = _gnutls_pubkey_compatible_with_sig(session, cert->pubkey, ver, sign_algo); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_session_sign_algo_enabled (session, sign_algo); if (ret < 0) return gnutls_assert_val(ret); hash_algo = _gnutls_sign_get_hash_algorithm (sign_algo); } else { ret = _gnutls_hash_init (&td_md5, GNUTLS_MAC_MD5); if (ret < 0) { gnutls_assert (); return ret; } _gnutls_hash (&td_md5, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); _gnutls_hash (&td_md5, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); _gnutls_hash (&td_md5, params->data, params->size); hash_algo = GNUTLS_DIG_SHA1; } ret = _gnutls_hash_init (&td_sha, hash_algo); if (ret < 0) { gnutls_assert (); if (!_gnutls_version_has_selectable_sighash (ver)) _gnutls_hash_deinit (&td_md5, NULL); return ret; } _gnutls_hash (&td_sha, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); _gnutls_hash (&td_sha, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); _gnutls_hash (&td_sha, params->data, params->size); if (!_gnutls_version_has_selectable_sighash (ver)) { _gnutls_hash_deinit (&td_md5, concat); _gnutls_hash_deinit (&td_sha, &concat[16]); dconcat.data = concat; dconcat.size = 36; } else { _gnutls_hash_deinit (&td_sha, concat); dconcat.data = concat; dconcat.size = _gnutls_hash_get_algo_len (hash_algo); } ret = verify_tls_hash (session, ver, cert, &dconcat, signature, dconcat.size - _gnutls_hash_get_algo_len (hash_algo), sign_algo, _gnutls_sign_get_pk_algorithm (sign_algo)); if (ret < 0) { gnutls_assert (); return ret; } return ret; } /* Client certificate verify calculations */ /* this is _gnutls_handshake_verify_crt_vrfy for TLS 1.2 */ static int _gnutls_handshake_verify_crt_vrfy12 (gnutls_session_t session, gnutls_pcert_st* cert, gnutls_datum_t * signature, gnutls_sign_algorithm_t sign_algo) { int ret; uint8_t concat[MAX_HASH_SIZE]; gnutls_datum_t dconcat; gnutls_digest_algorithm_t hash_algo; gnutls_protocol_t ver = gnutls_protocol_get_version (session); gnutls_pk_algorithm_t pk = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL); ret = _gnutls_session_sign_algo_enabled(session, sign_algo); if (ret < 0) return gnutls_assert_val(ret); hash_algo = _gnutls_sign_get_hash_algorithm(sign_algo); ret = _gnutls_hash_fast(hash_algo, session->internals.handshake_hash_buffer.data, session->internals.handshake_hash_buffer_prev_len, concat); if (ret < 0) return gnutls_assert_val(ret); dconcat.data = concat; dconcat.size = _gnutls_hash_get_algo_len (hash_algo); ret = verify_tls_hash (session, ver, cert, &dconcat, signature, 0, sign_algo, pk); if (ret < 0) { gnutls_assert (); return ret; } return ret; } /* Verifies a TLS signature (like the one in the client certificate * verify message). */ int _gnutls_handshake_verify_crt_vrfy (gnutls_session_t session, gnutls_pcert_st *cert, gnutls_datum_t * signature, gnutls_sign_algorithm_t sign_algo) { int ret; uint8_t concat[MAX_SIG_SIZE]; digest_hd_st td_md5; digest_hd_st td_sha; gnutls_datum_t dconcat; gnutls_protocol_t ver = gnutls_protocol_get_version (session); _gnutls_handshake_log ("HSK[%p]: verify cert vrfy: using %s\n", session, gnutls_sign_algorithm_get_name (sign_algo)); if (_gnutls_version_has_selectable_sighash(ver)) return _gnutls_handshake_verify_crt_vrfy12 (session, cert, signature, sign_algo); ret = _gnutls_hash_init (&td_md5, GNUTLS_DIG_MD5); if (ret < 0) { gnutls_assert (); return ret; } ret = _gnutls_hash_init (&td_sha, GNUTLS_DIG_SHA1); if (ret < 0) { gnutls_assert (); _gnutls_hash_deinit (&td_md5, NULL); return GNUTLS_E_HASH_FAILED; } _gnutls_hash(&td_sha, session->internals.handshake_hash_buffer.data, session->internals.handshake_hash_buffer_prev_len); _gnutls_hash(&td_md5, session->internals.handshake_hash_buffer.data, session->internals.handshake_hash_buffer_prev_len); if (ver == GNUTLS_SSL3) { ret = _gnutls_generate_master (session, 1); if (ret < 0) { _gnutls_hash_deinit (&td_md5, NULL); _gnutls_hash_deinit (&td_sha, NULL); return gnutls_assert_val(ret); } ret = _gnutls_mac_deinit_ssl3_handshake (&td_md5, concat, session-> security_parameters.master_secret, GNUTLS_MASTER_SIZE); if (ret < 0) { _gnutls_hash_deinit (&td_sha, NULL); return gnutls_assert_val(ret); } ret = _gnutls_mac_deinit_ssl3_handshake (&td_sha, &concat[16], session-> security_parameters.master_secret, GNUTLS_MASTER_SIZE); if (ret < 0) { return gnutls_assert_val(ret); } } else { _gnutls_hash_deinit (&td_md5, concat); _gnutls_hash_deinit (&td_sha, &concat[16]); } dconcat.data = concat; dconcat.size = 20 + 16; /* md5+ sha */ ret = verify_tls_hash (session, ver, cert, &dconcat, signature, 16, GNUTLS_SIGN_UNKNOWN, gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL)); if (ret < 0) { gnutls_assert (); return ret; } return ret; } /* the same as _gnutls_handshake_sign_crt_vrfy except that it is made for TLS 1.2 */ static int _gnutls_handshake_sign_crt_vrfy12 (gnutls_session_t session, gnutls_pcert_st* cert, gnutls_privkey_t pkey, gnutls_datum_t * signature) { gnutls_datum_t dconcat; int ret; uint8_t concat[MAX_SIG_SIZE]; gnutls_sign_algorithm_t sign_algo; gnutls_digest_algorithm_t hash_algo; sign_algo = _gnutls_session_get_sign_algo (session, cert); if (sign_algo == GNUTLS_SIGN_UNKNOWN) { gnutls_assert (); return GNUTLS_E_UNKNOWN_PK_ALGORITHM; } hash_algo = _gnutls_sign_get_hash_algorithm (sign_algo); _gnutls_debug_log ("sign handshake cert vrfy: picked %s with %s\n", gnutls_sign_algorithm_get_name (sign_algo), gnutls_mac_get_name ((gnutls_mac_algorithm_t)hash_algo)); ret = _gnutls_hash_fast (hash_algo, session->internals.handshake_hash_buffer.data, session->internals.handshake_hash_buffer.length, concat); if (ret < 0) return gnutls_assert_val(ret); dconcat.data = concat; dconcat.size = _gnutls_hash_get_algo_len (hash_algo); ret = sign_tls_hash (session, hash_algo, cert, pkey, &dconcat, signature); if (ret < 0) { gnutls_assert (); return ret; } return sign_algo; } /* Generates a signature of all the previous sent packets in the * handshake procedure. * 20040227: now it works for SSL 3.0 as well * 20091031: works for TLS 1.2 too! * * For TLS1.x, x<2 returns negative for failure and zero or unspecified for success. * For TLS1.2 returns the signature algorithm used on success, or a negative error code; */ int _gnutls_handshake_sign_crt_vrfy (gnutls_session_t session, gnutls_pcert_st* cert, gnutls_privkey_t pkey, gnutls_datum_t * signature) { gnutls_datum_t dconcat; int ret; uint8_t concat[MAX_SIG_SIZE]; digest_hd_st td_md5; digest_hd_st td_sha; gnutls_protocol_t ver = gnutls_protocol_get_version (session); gnutls_pk_algorithm_t pk = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL); if (_gnutls_version_has_selectable_sighash(ver)) return _gnutls_handshake_sign_crt_vrfy12 (session, cert, pkey, signature); ret = _gnutls_hash_init (&td_sha, GNUTLS_DIG_SHA1); if (ret < 0) { gnutls_assert (); return ret; } _gnutls_hash(&td_sha, session->internals.handshake_hash_buffer.data, session->internals.handshake_hash_buffer.length); if (ver == GNUTLS_SSL3) { ret = _gnutls_generate_master (session, 1); if (ret < 0) { gnutls_assert (); _gnutls_hash_deinit (&td_sha, NULL); return ret; } ret = _gnutls_mac_deinit_ssl3_handshake (&td_sha, &concat[16], session-> security_parameters.master_secret, GNUTLS_MASTER_SIZE); if (ret < 0) return gnutls_assert_val(ret); } else _gnutls_hash_deinit (&td_sha, &concat[16]); /* ensure 1024 bit DSA keys are used */ ret = _gnutls_pubkey_compatible_with_sig(session, cert->pubkey, ver, GNUTLS_SIGN_UNKNOWN); if (ret < 0) return gnutls_assert_val(ret); switch (pk) { case GNUTLS_PK_RSA: ret = _gnutls_hash_init (&td_md5, GNUTLS_DIG_MD5); if (ret < 0) return gnutls_assert_val(ret); _gnutls_hash(&td_md5, session->internals.handshake_hash_buffer.data, session->internals.handshake_hash_buffer.length); if (ver == GNUTLS_SSL3) { ret = _gnutls_mac_deinit_ssl3_handshake (&td_md5, concat, session-> security_parameters.master_secret, GNUTLS_MASTER_SIZE); if (ret < 0) return gnutls_assert_val(ret); } else _gnutls_hash_deinit (&td_md5, concat); dconcat.data = concat; dconcat.size = 36; break; case GNUTLS_PK_DSA: case GNUTLS_PK_EC: dconcat.data = &concat[16]; dconcat.size = 20; break; default: return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); } ret = sign_tls_hash (session, GNUTLS_DIG_NULL, cert, pkey, &dconcat, signature); if (ret < 0) { gnutls_assert (); } return ret; } int pk_hash_data (gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t hash, gnutls_pk_params_st* params, const gnutls_datum_t * data, gnutls_datum_t * digest) { int ret; digest->size = _gnutls_hash_get_algo_len (hash); digest->data = gnutls_malloc (digest->size); if (digest->data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_hash_fast (hash, data->data, data->size, digest->data); if (ret < 0) { gnutls_assert (); goto cleanup; } return 0; cleanup: gnutls_free (digest->data); return ret; } /* * This function will do RSA PKCS #1 1.5 encoding * on the given digest. The given digest must be allocated * and will be freed if replacement is required. */ int pk_prepare_hash (gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t hash, gnutls_datum_t * digest) { int ret; gnutls_datum_t old_digest = { digest->data, digest->size }; switch (pk) { case GNUTLS_PK_RSA: /* Encode the digest as a DigestInfo */ if ((ret = encode_ber_digest_info (hash, &old_digest, digest)) != 0) { gnutls_assert (); return ret; } _gnutls_free_datum (&old_digest); break; case GNUTLS_PK_DSA: case GNUTLS_PK_EC: break; default: gnutls_assert (); return GNUTLS_E_UNIMPLEMENTED_FEATURE; } 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 (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; }