diff options
author | Simon Josefsson <simon@josefsson.org> | 2008-12-11 08:33:04 +0100 |
---|---|---|
committer | Simon Josefsson <simon@josefsson.org> | 2008-12-11 08:33:04 +0100 |
commit | e311252bf0dd32fb2ca52e327763ae856e54e3f7 (patch) | |
tree | 5f98439ab77ad684171cca7460c3add494938a44 /lib | |
parent | 894e7471ab51c30f67f379f9b80530b9a9d22b11 (diff) | |
download | gnutls-e311252bf0dd32fb2ca52e327763ae856e54e3f7.tar.gz |
gnutls: New interface to get key id for certificate requests.
Patch from David Marín Carreño <davefx@gmail.com> in
<http://thread.gmane.org/gmane.comp.encryption.gpg.gnutls.devel/3321>.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/includes/gnutls/x509.h | 3 | ||||
-rw-r--r-- | lib/x509/crq.c | 159 |
2 files changed, 162 insertions, 0 deletions
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 */ |