From e311252bf0dd32fb2ca52e327763ae856e54e3f7 Mon Sep 17 00:00:00 2001 From: Simon Josefsson Date: Thu, 11 Dec 2008 08:33:04 +0100 Subject: =?UTF-8?q?gnutls:=20New=20interface=20to=20get=20key=20id=20for?= =?UTF-8?q?=20certificate=20requests.=20Patch=20from=20David=20Mar=C3=ADn?= =?UTF-8?q?=20Carre=C3=B1o=20=20in=20.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AUTHORS | 3 + NEWS | 9 +++ lib/includes/gnutls/x509.h | 3 + lib/x509/crq.c | 159 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+) diff --git a/AUTHORS b/AUTHORS index 456f4c6c60..539ef072bf 100644 --- a/AUTHORS +++ b/AUTHORS @@ -48,6 +48,9 @@ Certificate name import/export, build fixes, test vectors. Daniel Kahn Gillmor OpenPGP discussion and improvements. +David Marín Carreño +Added gnutls_x509_crq_get_key_id. + -----BEGIN PGP PUBLIC KEY BLOCK----- URL: http://josefsson.org/key.txt (always latest version) Comment: This 0xB565716F key is used to sign releases of GnuTLS. diff --git a/NEWS b/NEWS index 0e14919c24..0c317d8ab3 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,15 @@ Copyright (C) 2004, 2005, 2006, 2007, 2008 Simon Josefsson Copyright (C) 2000, 2001, 2002, 2003, 2004 Nikos Mavrogiannopoulos See the end for copying conditions. +* Version 2.7.4 (unreleased) + +** gnutls: New interface to get key id for certificate requests. +Patch from David Marín Carreño in +. + +** API and ABI modifications: +gnutls_x509_crq_get_key_id: ADDED. + * Version 2.7.3 (released 2008-12-10) ** gnutls: Fix chain verification for chains that ends with RSA-MD2 CAs. diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h index 63da3201cb..00c62a609b 100644 --- a/lib/includes/gnutls/x509.h +++ b/lib/includes/gnutls/x509.h @@ -738,6 +738,9 @@ extern "C" int gnutls_x509_crq_get_pk_algorithm (gnutls_x509_crq_t crq, unsigned int *bits); + int gnutls_x509_crq_get_key_id (gnutls_x509_crq_t crq, unsigned int flags, + unsigned char *output_data, + size_t * output_data_size); int gnutls_x509_crq_get_key_rsa_raw (gnutls_x509_crq_t crq, gnutls_datum_t * m, gnutls_datum_t * e); diff --git a/lib/x509/crq.c b/lib/x509/crq.c index a6cfa3e57a..b5cb7911ad 100644 --- a/lib/x509/crq.c +++ b/lib/x509/crq.c @@ -2234,4 +2234,163 @@ gnutls_x509_crq_set_key_purpose_oid (gnutls_x509_crq_t cert, return 0; } +static int +rsadsa_crq_get_key_id (gnutls_x509_crq_t crq, int pk, + unsigned char *output_data, size_t * output_data_size) +{ + bigint_t params[MAX_PUBLIC_PARAMS_SIZE]; + int params_size = MAX_PUBLIC_PARAMS_SIZE; + int i, result = 0; + gnutls_datum_t der = { NULL, 0 }; + digest_hd_st hd; + + result = _gnutls_x509_crq_get_mpis (crq, params, ¶ms_size); + if (result < 0) + { + gnutls_assert (); + return result; + } + + if (pk == GNUTLS_PK_RSA) + { + result = _gnutls_x509_write_rsa_params (params, params_size, &der); + if (result < 0) + { + gnutls_assert (); + goto cleanup; + } + } + else if (pk == GNUTLS_PK_DSA) + { + result = _gnutls_x509_write_dsa_public_key (params, params_size, &der); + if (result < 0) + { + gnutls_assert (); + goto cleanup; + } + } + else + return GNUTLS_E_INTERNAL_ERROR; + + result = _gnutls_hash_init (&hd, GNUTLS_MAC_SHA1); + if (result < 0) + { + gnutls_assert (); + goto cleanup; + } + + _gnutls_hash (&hd, der.data, der.size); + + _gnutls_hash_deinit (&hd, output_data); + *output_data_size = 20; + + result = 0; + +cleanup: + + _gnutls_free_datum (&der); + + /* release all allocated MPIs + */ + for (i = 0; i < params_size; i++) + { + _gnutls_mpi_release (¶ms[i]); + } + return result; +} + +/** + * gnutls_x509_crq_get_key_id - Return unique ID of public key's parameters + * @crq: Holds the certificate signing request + * @flags: should be 0 for now + * @output_data: will contain the key ID + * @output_data_size: holds the size of output_data (and will be + * replaced by the actual size of parameters) + * + * This function will return a unique ID the depends on the public + * key parameters. This ID can be used in checking whether a + * certificate corresponds to the given private key. + * + * If the buffer provided is not long enough to hold the output, then + * *output_data_size is updated and GNUTLS_E_SHORT_MEMORY_BUFFER will + * be returned. The output will normally be a SHA-1 hash output, + * which is 20 bytes. + * + * Return value: In case of failure a negative value will be + * returned, and 0 on success. + * + * Since: 2.8.0 + **/ +int +gnutls_x509_crq_get_key_id (gnutls_x509_crq_t crq, unsigned int flags, + unsigned char *output_data, + size_t * output_data_size) +{ + int pk, result = 0; + gnutls_datum_t pubkey; + + if (crq == NULL) + { + gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + if (*output_data_size < 20) + { + gnutls_assert (); + *output_data_size = 20; + return GNUTLS_E_SHORT_MEMORY_BUFFER; + } + + pk = gnutls_x509_crq_get_pk_algorithm (crq, NULL); + if (pk < 0) + { + gnutls_assert (); + return pk; + } + + if (pk == GNUTLS_PK_RSA || pk == GNUTLS_PK_DSA) + { + /* This is for compatibility with what GnuTLS has printed for + RSA/DSA before the code below was added. The code below is + applicable to all types, and it would probably be a better + idea to use it for RSA/DSA too, but doing so would break + backwards compatibility. */ + return rsadsa_crq_get_key_id (crq, pk, output_data, output_data_size); + } + + pubkey.size = 0; + result = asn1_der_coding (crq->crq, "certificationRequestInfo.subjectPKInfo", + NULL, &pubkey.size, NULL); + if (result != ASN1_MEM_ERROR) + { + gnutls_assert (); + return _gnutls_asn2err (result); + } + + pubkey.data = gnutls_malloc (pubkey.size); + if (pubkey.data == NULL) + { + gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + result = asn1_der_coding (crq->crq, "certificationRequestInfo.subjectPKInfo", + pubkey.data, &pubkey.size, NULL); + if (result != ASN1_SUCCESS) + { + gnutls_assert (); + gnutls_free (pubkey.data); + return _gnutls_asn2err (result); + } + + result = gnutls_fingerprint (GNUTLS_DIG_SHA1, &pubkey, + output_data, output_data_size); + + gnutls_free (pubkey.data); + + return result; +} + + #endif /* ENABLE_PKI */ -- cgit v1.2.1