diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-03-14 12:53:16 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-03-14 12:53:16 +0000 |
commit | dc7e1c02d1e2a65673f2102eaeb2ca9c9a4e7bc6 (patch) | |
tree | becb0242224c3ca84b7f52b2d35241b7caea27f8 | |
parent | 932b1d116bb19c629b4fc9646d9525e52ba157f2 (diff) | |
download | gnutls-dc7e1c02d1e2a65673f2102eaeb2ca9c9a4e7bc6.tar.gz |
Added some stuff needed in PKCS#10 certificate request generation. Some other fixes as well.
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/auth_cert.c | 2 | ||||
-rw-r--r-- | lib/auth_dhe.c | 6 | ||||
-rw-r--r-- | lib/auth_rsa.c | 2 | ||||
-rw-r--r-- | lib/auth_rsa_export.c | 6 | ||||
-rw-r--r-- | lib/gnutls_pk.c | 12 | ||||
-rw-r--r-- | lib/gnutls_pk.h | 2 | ||||
-rw-r--r-- | lib/gnutls_sig.c | 49 | ||||
-rw-r--r-- | lib/gnutls_sig.h | 6 | ||||
-rw-r--r-- | lib/pkix.asn | 19 | ||||
-rw-r--r-- | lib/pkix_asn1_tab.c | 15 | ||||
-rw-r--r-- | lib/x509/Makefile.am | 7 | ||||
-rw-r--r-- | lib/x509/crl.c | 19 | ||||
-rw-r--r-- | lib/x509/crq.c | 226 | ||||
-rw-r--r-- | lib/x509/crq.h | 19 | ||||
-rw-r--r-- | lib/x509/pkcs7.c | 27 | ||||
-rw-r--r-- | lib/x509/privkey.c | 73 | ||||
-rw-r--r-- | lib/x509/sign.c | 193 | ||||
-rw-r--r-- | lib/x509/sign.h | 2 | ||||
-rw-r--r-- | lib/x509/verify.c | 15 | ||||
-rw-r--r-- | lib/x509/x509.c | 98 | ||||
-rw-r--r-- | lib/x509/x509.h | 7 |
22 files changed, 656 insertions, 151 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index ff45038379..768930d466 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -49,7 +49,7 @@ libgnutls_la_SOURCES = $(COBJECTS) libgnutls_la_LIBADD = $(MINITASN1_OBJECTS) x509/dn.lo x509/crl.lo x509/common.lo \ x509/x509.lo x509/pkcs7.lo x509/extensions.lo x509/compat.lo x509/verify.lo \ - x509/mpi.lo x509/privkey.lo + x509/mpi.lo x509/privkey.lo x509/crq.lo x509/sign.lo libgnutls_la_LDFLAGS = $(LIBASN1_LINK) $(LIBGCRYPT_LIBS) \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) #-export-symbols gnutls.sym diff --git a/lib/auth_cert.c b/lib/auth_cert.c index c20be5aff9..37bdf5bc61 100644 --- a/lib/auth_cert.c +++ b/lib/auth_cert.c @@ -1055,7 +1055,7 @@ int _gnutls_gen_cert_client_cert_vrfy(gnutls_session session, if (apr_pkey != NULL) { if ((ret = - _gnutls_generate_sig_from_hdata(session, + _gnutls_tls_sign_hdata(session, &apr_cert_list[0], apr_pkey, &signature)) < 0) { diff --git a/lib/auth_dhe.c b/lib/auth_dhe.c index 4e7323297a..d495311c53 100644 --- a/lib/auth_dhe.c +++ b/lib/auth_dhe.c @@ -1,7 +1,7 @@ /* - * Copyright (C) 2000,2001,2002,2003 Nikos Mavroyanopoulos + * Copyright (C) 2000,2001,2002,2003 Nikos Mavroyanopoulos * - * This file is part of GNUTLS. + * This file is part of GNUTLS. * * The GNUTLS library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -141,7 +141,7 @@ static int gen_dhe_server_kx(gnutls_session session, opaque ** data) if (apr_pkey != NULL) { if ((ret = - _gnutls_generate_sig_params(session, &apr_cert_list[0], + _gnutls_tls_sign_params(session, &apr_cert_list[0], apr_pkey, &ddata, &signature)) < 0) { gnutls_assert(); diff --git a/lib/auth_rsa.c b/lib/auth_rsa.c index 1c1ec48a08..961adde5d7 100644 --- a/lib/auth_rsa.c +++ b/lib/auth_rsa.c @@ -306,7 +306,7 @@ int _gnutls_gen_rsa_client_kx(gnutls_session session, opaque ** data) } if ((ret = - _gnutls_pkcs1_rsa_encrypt(&sdata, session->key->key, + _gnutls_pkcs1_rsa_encrypt(&sdata, &session->key->key, params, params_len, 2)) < 0) { gnutls_assert(); return ret; diff --git a/lib/auth_rsa_export.c b/lib/auth_rsa_export.c index 6445fd844f..b57def2cff 100644 --- a/lib/auth_rsa_export.c +++ b/lib/auth_rsa_export.c @@ -1,7 +1,7 @@ /* - * Copyright (C) 2000,2001,2002,2003 Nikos Mavroyanopoulos + * Copyright (C) 2000,2001,2002,2003 Nikos Mavroyanopoulos * - * This file is part of GNUTLS. + * This file is part of GNUTLS. * * The GNUTLS library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -148,7 +148,7 @@ static int gen_rsa_export_server_kx(gnutls_session session, opaque ** data) if (apr_pkey != NULL) { if ((ret = - _gnutls_generate_sig_params(session, &apr_cert_list[0], + _gnutls_tls_sign_params(session, &apr_cert_list[0], apr_pkey, &ddata, &signature)) < 0) { gnutls_assert(); diff --git a/lib/gnutls_pk.c b/lib/gnutls_pk.c index 1b538301e3..7aa969f2d7 100644 --- a/lib/gnutls_pk.c +++ b/lib/gnutls_pk.c @@ -1,7 +1,7 @@ /* - * Copyright (C) 2001,2002,2003 Nikos Mavroyanopoulos + * Copyright (C) 2001,2002,2003 Nikos Mavroyanopoulos * - * This file is part of GNUTLS. + * This file is part of GNUTLS. * * The GNUTLS library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -42,7 +42,7 @@ static int _gnutls_pk_decrypt(int algo, GNUTLS_MPI * resarr, GNUTLS_MPI data, GN * params is modulus, public exp. */ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, - gnutls_datum plaintext, GNUTLS_MPI* params, + const gnutls_datum *plaintext, GNUTLS_MPI* params, uint params_len, uint btype) { @@ -57,7 +57,7 @@ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, k = mod_bits / 8; if ( mod_bits % 8 != 0) k++; - if (plaintext.size > k - 11) { + if (plaintext->size > k - 11) { gnutls_assert(); return GNUTLS_E_PK_ENCRYPTION_FAILED; } @@ -74,7 +74,7 @@ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, edata[0] = 0; edata[1] = btype; - psize = k - 3 - plaintext.size; + psize = k - 3 - plaintext->size; ps = &edata[2]; switch (btype) { @@ -111,7 +111,7 @@ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, } ps[psize] = 0; - memcpy(&ps[psize + 1], plaintext.data, plaintext.size); + memcpy(&ps[psize + 1], plaintext->data, plaintext->size); if (_gnutls_mpi_scan(&m, edata, &k) != 0) { gnutls_assert(); diff --git a/lib/gnutls_pk.h b/lib/gnutls_pk.h index 30483992ad..d3b14315e6 100644 --- a/lib/gnutls_pk.h +++ b/lib/gnutls_pk.h @@ -1,7 +1,7 @@ #ifndef GNUTLS_PK_H # define GNUTLS_PK_H -int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext, +int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, const gnutls_datum *plaintext, MPI * params, uint params_len, uint btype); int _gnutls_dsa_sign(gnutls_datum * signature, const gnutls_datum *plaintext, MPI *params, uint params_len); diff --git a/lib/gnutls_sig.c b/lib/gnutls_sig.c index a70d1fd2ad..07f4b80825 100644 --- a/lib/gnutls_sig.c +++ b/lib/gnutls_sig.c @@ -34,13 +34,14 @@ #include <gnutls_sig.h> -int _gnutls_generate_sig( gnutls_cert* cert, gnutls_privkey* pkey, const gnutls_datum* hash_concat, gnutls_datum *signature); +static +int _gnutls_tls_sign( gnutls_cert* cert, gnutls_privkey* pkey, const gnutls_datum* hash_concat, gnutls_datum *signature); /* Generates a signature of all the previous sent packets in the * handshake procedure. */ -int _gnutls_generate_sig_from_hdata( gnutls_session session, gnutls_cert* cert, gnutls_privkey* pkey, gnutls_datum *signature) { +int _gnutls_tls_sign_hdata( gnutls_session session, gnutls_cert* cert, gnutls_privkey* pkey, gnutls_datum *signature) { gnutls_datum dconcat; int ret; opaque concat[36]; @@ -77,7 +78,7 @@ GNUTLS_MAC_HANDLE td_sha; gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } - ret = _gnutls_generate_sig( cert, pkey, &dconcat, signature); + ret = _gnutls_tls_sign( cert, pkey, &dconcat, signature); if (ret < 0) gnutls_assert(); @@ -88,7 +89,7 @@ GNUTLS_MAC_HANDLE td_sha; /* Generates a signature of all the random data and the parameters. * Used in DHE_* ciphersuites. */ -int _gnutls_generate_sig_params( gnutls_session session, gnutls_cert* cert, gnutls_privkey* pkey, gnutls_datum* params, gnutls_datum *signature) +int _gnutls_tls_sign_params( gnutls_session session, gnutls_cert* cert, gnutls_privkey* pkey, gnutls_datum* params, gnutls_datum *signature) { gnutls_datum dconcat; int ret; @@ -135,7 +136,7 @@ opaque concat[36]; gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } - ret = _gnutls_generate_sig( cert, pkey, &dconcat, signature); + ret = _gnutls_tls_sign( cert, pkey, &dconcat, signature); if (ret < 0) gnutls_assert(); @@ -148,10 +149,9 @@ opaque concat[36]; * Cert is the certificate of the corresponding private key. It is only checked if * it supports signing. */ -int _gnutls_generate_sig( gnutls_cert* cert, gnutls_privkey* pkey, const gnutls_datum* hash_concat, gnutls_datum *signature) +static +int _gnutls_tls_sign( gnutls_cert* cert, gnutls_privkey* pkey, const gnutls_datum* hash_concat, gnutls_datum *signature) { -int ret; -gnutls_datum tmpdata; /* If our certificate supports signing */ @@ -163,14 +163,25 @@ gnutls_datum tmpdata; return GNUTLS_E_KEY_USAGE_VIOLATION; } - tmpdata.data = hash_concat->data; - tmpdata.size = hash_concat->size; + return _gnutls_sign( pkey->pk_algorithm, pkey->params, pkey->params_size, + hash_concat, signature); + +} + + +/* 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_sign( gnutls_pk_algorithm algo, GNUTLS_MPI* params, int params_size, + const gnutls_datum* data, gnutls_datum *signature) +{ +int ret; - switch(pkey->pk_algorithm) { + switch(algo) { case GNUTLS_PK_RSA: /* encrypt */ - if ((ret=_gnutls_pkcs1_rsa_encrypt( signature, tmpdata, pkey->params, - pkey->params_size, 1)) < 0) { + if ((ret=_gnutls_pkcs1_rsa_encrypt( signature, data, params, + params_size, 1)) < 0) { gnutls_assert(); return ret; } @@ -178,8 +189,8 @@ gnutls_datum tmpdata; break; case GNUTLS_PK_DSA: /* sign */ - if ((ret=_gnutls_dsa_sign( signature, &tmpdata, pkey->params, - pkey->params_size)) < 0) { + if ((ret=_gnutls_dsa_sign( signature, data, params, + params_size)) < 0) { gnutls_assert(); return ret; } @@ -190,14 +201,14 @@ gnutls_datum tmpdata; break; } - - return 0; } - -int _gnutls_pkcs1_rsa_verify_sig( gnutls_cert *cert, const gnutls_datum *hash_concat, gnutls_datum *signature) { +static +int _gnutls_pkcs1_rsa_verify_sig( gnutls_cert *cert, const gnutls_datum *hash_concat, + gnutls_datum *signature) +{ int ret; gnutls_datum vdata; diff --git a/lib/gnutls_sig.h b/lib/gnutls_sig.h index e839c38d88..30feba7b43 100644 --- a/lib/gnutls_sig.h +++ b/lib/gnutls_sig.h @@ -3,9 +3,11 @@ # include <auth_cert.h> gnutls_certificate_status gnutls_x509_verify_signature(gnutls_cert* cert, gnutls_cert* issuer); -int _gnutls_generate_sig_from_hdata( gnutls_session session, gnutls_cert* cert, gnutls_privkey *pkey, gnutls_datum *signature); -int _gnutls_generate_sig_params( gnutls_session session, gnutls_cert* cert, gnutls_privkey *pkey, gnutls_datum* params, gnutls_datum *signature); +int _gnutls_tls_sign_hdata( gnutls_session session, gnutls_cert* cert, gnutls_privkey *pkey, gnutls_datum *signature); +int _gnutls_tls_sign_params( gnutls_session session, gnutls_cert* cert, gnutls_privkey *pkey, gnutls_datum* params, gnutls_datum *signature); int _gnutls_verify_sig_hdata( gnutls_session session, gnutls_cert *cert, gnutls_datum* signature); int _gnutls_verify_sig_params( gnutls_session session, gnutls_cert *cert, const gnutls_datum* params, gnutls_datum* signature); +int _gnutls_sign( gnutls_pk_algorithm algo, GNUTLS_MPI* params, int params_size, + const gnutls_datum* data, gnutls_datum *signature); #endif diff --git a/lib/pkix.asn b/lib/pkix.asn index 6cf70a7c82..e628b190ce 100644 --- a/lib/pkix.asn +++ b/lib/pkix.asn @@ -980,4 +980,23 @@ CertificateSet ::= SET OF CertificateChoices SignerInfos ::= SET OF ANY -- this is not correct but we don't use it -- anyway + +-- BEGIN of RFC2986 + +-- Certificate requests +CertificationRequestInfo ::= SEQUENCE { + version INTEGER { v1(0) }, + subject Name, + subjectPKInfo SubjectPublicKeyInfo, + attributes [0] Attributes +} + +Attributes ::= SET OF Attribute + +CertificationRequest ::= SEQUENCE { + certificationRequestInfo CertificationRequestInfo, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING +} + END diff --git a/lib/pkix_asn1_tab.c b/lib/pkix_asn1_tab.c index 2958e8f871..e1d489c3c0 100644 --- a/lib/pkix_asn1_tab.c +++ b/lib/pkix_asn1_tab.c @@ -896,7 +896,20 @@ const ASN1_ARRAY_TYPE pkix_asn1_tab[]={ {"certificate",2,"Certificate"}, {"CertificateSet",1610612751,0}, {0,2,"CertificateChoices"}, - {"SignerInfos",536870927,0}, + {"SignerInfos",1610612751,0}, {0,13,0}, + {"CertificationRequestInfo",1610612741,0}, + {"version",1610874883,0}, + {"v1",1,"0"}, + {"subject",1073741826,"Name"}, + {"subjectPKInfo",1073741826,"SubjectPublicKeyInfo"}, + {"attributes",536879106,"Attributes"}, + {0,4104,"0"}, + {"Attributes",1610612751,0}, + {0,2,"Attribute"}, + {"CertificationRequest",536870917,0}, + {"certificationRequestInfo",1073741826,"CertificationRequestInfo"}, + {"signatureAlgorithm",1073741826,"AlgorithmIdentifier"}, + {"signature",6,0}, {0,0,0} }; diff --git a/lib/x509/Makefile.am b/lib/x509/Makefile.am index 8165cfc3bd..a84013b1c8 100644 --- a/lib/x509/Makefile.am +++ b/lib/x509/Makefile.am @@ -1,11 +1,12 @@ INCLUDES = -I../ -I../minitasn1/ -I../../includes/ EXTRA_DIST = dn.h common.h x509.h extensions.h pkcs7.h \ - x509-api.tex compat.h verify.h mpi.h + x509-api.tex compat.h verify.h mpi.h crq.h sign.h noinst_LTLIBRARIES = libx509.la -COBJECTS = crl.c dn.c common.c x509.c extensions.c \ - pkcs7.c xml.c rfc2818_hostname.c verify.c mpi.c privkey.c +COBJECTS = crl.c dn.c common.c x509.c extensions.c crq.c \ + pkcs7.c xml.c rfc2818_hostname.c verify.c mpi.c privkey.c \ + sign.c COMPAT_OBJECTS = compat.c diff --git a/lib/x509/crl.c b/lib/x509/crl.c index 52506b182a..436f3832a7 100644 --- a/lib/x509/crl.c +++ b/lib/x509/crl.c @@ -44,7 +44,13 @@ int gnutls_x509_crl_init(gnutls_x509_crl * crl) *crl = gnutls_calloc(1, sizeof(gnutls_x509_crl_int)); if (*crl) { - (*crl)->crl = ASN1_TYPE_EMPTY; + int result = asn1_create_element(_gnutls_get_pkix(), + "PKIX1.CertificateList", + &(*crl)->crl); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } return 0; /* success */ } return GNUTLS_E_MEMORY_ERROR; @@ -110,15 +116,6 @@ int gnutls_x509_crl_import(gnutls_x509_crl crl, const gnutls_datum * data, need_free = 1; } - crl->crl = ASN1_TYPE_EMPTY; - - result = asn1_create_element(_gnutls_get_pkix(), - "PKIX1.CertificateList", - &crl->crl); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } result = asn1_der_decoding(&crl->crl, _data.data, _data.size, NULL); @@ -205,8 +202,6 @@ int gnutls_x509_crl_import(gnutls_x509_crl crl, const gnutls_datum * data, return 0; cleanup: - if (crl->crl) - asn1_delete_structure(&crl->crl); _gnutls_free_datum(&crl->signed_data); _gnutls_free_datum(&crl->signature); if (need_free) diff --git a/lib/x509/crq.c b/lib/x509/crq.c new file mode 100644 index 0000000000..5fe2d1591a --- /dev/null +++ b/lib/x509/crq.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2003 Nikos Mavroyanopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* This file contains functions to handle PKCS #10 certificate requests. + */ + +#include <gnutls_int.h> +#include <gnutls_datum.h> +#include <gnutls_global.h> +#include <gnutls_errors.h> +#include <common.h> +#include <gnutls_x509.h> +#include <x509_b64.h> +#include <crq.h> +#include <dn.h> +#include <extensions.h> +#include <libtasn1.h> +#include <gnutls_ui.h> + +/** + * gnutls_x509_crq_init - This function initializes a gnutls_x509_crq structure + * @crq: The structure to be initialized + * + * This function will initialize a PKCS10 certificate request structure. + * + * Returns 0 on success. + * + **/ +int gnutls_x509_crq_init(gnutls_x509_crq * crq) +{ + *crq = gnutls_calloc( 1, sizeof(gnutls_x509_crq_int)); + + if (*crq) { + int result = asn1_create_element(_gnutls_get_pkix(), + "PKIX1.CertificationRequest", + &((*crq)->crq)); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + return 0; /* success */ + } + return GNUTLS_E_MEMORY_ERROR; +} + +/** + * gnutls_x509_crq_deinit - This function deinitializes memory used by a gnutls_x509_crq structure + * @crq: The structure to be initialized + * + * This function will deinitialize a CRL structure. + * + **/ +void gnutls_x509_crq_deinit(gnutls_x509_crq crq) +{ + if (crq->crq) + asn1_delete_structure(&crq->crq); + + gnutls_free(crq); +} + +#define PEM_CRQ "CERTIFICATE REQUEST" + +/** + * gnutls_x509_crq_import - This function will import a DER or PEM encoded Certificate request + * @crq: The structure to store the parsed certificate request. + * @data: The DER or PEM encoded certificate. + * @format: One of DER or PEM + * + * This function will convert the given DER or PEM encoded Certificate + * to the native gnutls_x509_crq format. The output will be stored in 'cert'. + * + * If the Certificate is PEM encoded it should have a header of "CERTIFICATE REQUEST". + * + * Returns 0 on success. + * + **/ +int gnutls_x509_crq_import(gnutls_x509_crq crq, const gnutls_datum * data, + gnutls_x509_crt_fmt format) +{ + int result = 0, need_free = 0; + gnutls_datum _data = { data->data, data->size }; + + /* If the Certificate is in PEM format then decode it + */ + if (format == GNUTLS_X509_FMT_PEM) { + opaque *out; + + /* Try the first header */ + result = _gnutls_fbase64_decode(PEM_CRQ, data->data, data->size, + &out); + + if (result <= 0) { + if (result==0) result = GNUTLS_E_INTERNAL_ERROR; + gnutls_assert(); + return result; + } + + _data.data = out; + _data.size = result; + + need_free = 1; + } + + result = asn1_der_decoding(&crq->crq, _data.data, _data.size, NULL); + if (result != ASN1_SUCCESS) { + result = _gnutls_asn2err(result); + gnutls_assert(); + goto cleanup; + } + + if (need_free) _gnutls_free_datum( &_data); + + return 0; + + cleanup: + if (need_free) _gnutls_free_datum( &_data); + return result; +} + + + +/** + * gnutls_x509_crq_get_dn - This function returns the Certificate request subject's distinguished name + * @crq: should contain a gnutls_x509_crq structure + * @buf: a pointer to a structure to hold the name (may be null) + * @sizeof_buf: initialy holds the size of 'buf' + * + * This function will copy the name of the Certificate request subject in the provided buffer. The name + * will be in the form "C=xxxx,O=yyyy,CN=zzzz" as described in RFC2253. + * + * If buf is null then only the size will be filled. + * + * Returns GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is not long enough, and + * in that case the sizeof_buf will be updated with the required size. + * On success zero is returned. + * + **/ +int gnutls_x509_crq_get_dn(gnutls_x509_crq crq, char *buf, + int *sizeof_buf) +{ + if (sizeof_buf == 0 || crq == NULL) { + return GNUTLS_E_INVALID_REQUEST; + } + + return _gnutls_x509_parse_dn( crq->crq, "certificationRequestInfo.subject.rdnSequence", + buf, sizeof_buf); + + +} + +/** + * gnutls_x509_crq_get_dn_by_oid - This function returns the Certificate request subject's distinguished name + * @crq: should contain a gnutls_x509_crq structure + * @oid: holds an Object Identified in null terminated string + * @indx: In case multiple same OIDs exist in the RDN, this specifies which to send. Use zero to get the first one. + * @buf: a pointer to a structure to hold the name (may be null) + * @sizeof_buf: initialy holds the size of 'buf' + * + * This function will extract the part of the name of the Certificate request subject, specified + * by the given OID. The output will be encoded as described in RFC2253. + * + * Some helper macros with popular OIDs can be found in gnutls/x509.h + * + * If buf is null then only the size will be filled. + * + * Returns GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is not long enough, and + * in that case the sizeof_buf will be updated with the required size. + * On success zero is returned. + * + **/ +int gnutls_x509_crq_get_dn_by_oid(gnutls_x509_crq crq, const char* oid, + int indx, char *buf, int *sizeof_buf) +{ + if (sizeof_buf == 0 || crq == NULL) { + return GNUTLS_E_INVALID_REQUEST; + } + + return _gnutls_x509_parse_dn_oid( crq->crq, "certificationRequestInfo.subject.rdnSequence", oid, + indx, buf, sizeof_buf); + + +} + +/** + * gnutls_x509_crq_export - This function will export the generated certificate request + * @crq: Holds the request + * @format: the format of output params. One of PEM or DER. + * @output_data: will contain a certificate request PEM or DER encoded + * @output_data_size: holds the size of output_data (and will be replaced by the actual size of parameters) + * + * This function will export the certificate request to a PKCS10 + * + * If the buffer provided is not long enough to hold the output, then + * GNUTLS_E_SHORT_MEMORY_BUFFER will be returned. + * + * If the structure is PEM encoded, it will have a header + * of "BEGIN CERTIFICATE REQUEST". + * + * In case of failure a negative value will be returned, and + * 0 on success. + * + **/ +int gnutls_x509_crq_export( gnutls_x509_crq crq, + gnutls_x509_crt_fmt format, unsigned char* output_data, int* output_data_size) +{ + return _gnutls_x509_export_int( crq->crq, format, PEM_CRQ, *output_data_size, + output_data, output_data_size); +} diff --git a/lib/x509/crq.h b/lib/x509/crq.h new file mode 100644 index 0000000000..58a14cf70e --- /dev/null +++ b/lib/x509/crq.h @@ -0,0 +1,19 @@ +#ifndef CRL_H +# define CRL_H + +typedef struct gnutls_x509_crq_int { + ASN1_TYPE crq; +} gnutls_x509_crq_int; + +typedef struct gnutls_x509_crq_int *gnutls_x509_crq; + +int gnutls_x509_crt_get_dn_by_oid(gnutls_x509_crt cert, const char* oid, + int indx, char *buf, int *sizeof_buf); + +int gnutls_x509_crq_init(gnutls_x509_crq * crq); +void gnutls_x509_crq_deinit(gnutls_x509_crq crq); + +int gnutls_x509_crq_import(gnutls_x509_crq crq, const gnutls_datum * data, + gnutls_x509_crt_fmt format); + +#endif diff --git a/lib/x509/pkcs7.c b/lib/x509/pkcs7.c index 67166ba16f..8f7d759107 100644 --- a/lib/x509/pkcs7.c +++ b/lib/x509/pkcs7.c @@ -19,6 +19,9 @@ * */ +/* Functions that relate on PKCS7 certificate lists parsing. + */ + #include <libtasn1.h> #include <gnutls_int.h> #include <gnutls_datum.h> @@ -33,8 +36,7 @@ * gnutls_pkcs7_init - This function initializes a gnutls_pkcs7 structure * @pkcs7: The structure to be initialized * - * This function will initialize a PKCS7 structure. PKCS7 stands for - * Certificate Revocation List. + * This function will initialize a PKCS7 structure. * * Returns 0 on success. * @@ -44,7 +46,13 @@ int gnutls_pkcs7_init(gnutls_pkcs7 * pkcs7) *pkcs7 = gnutls_calloc( 1, sizeof(gnutls_pkcs7_int)); if (*pkcs7) { - (*pkcs7)->pkcs7 = ASN1_TYPE_EMPTY; + int result = asn1_create_element(_gnutls_get_pkix(), + "PKIX1.ContentInfo", + &(*pkcs7)->pkcs7); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } return 0; /* success */ } return GNUTLS_E_MEMORY_ERROR; @@ -74,7 +82,7 @@ void gnutls_pkcs7_deinit(gnutls_pkcs7 pkcs7) * This function will convert the given DER or PEM encoded PKCS7 * to the native gnutls_pkcs7 format. The output will be stored in 'pkcs7'. * - * If the PKCS7 is PEM encoded it should have a header of "X509 PKCS7". + * If the PKCS7 is PEM encoded it should have a header of "PKCS7". * * Returns 0 on success. * @@ -105,15 +113,6 @@ int gnutls_pkcs7_import(gnutls_pkcs7 pkcs7, const gnutls_datum * data, need_free = 1; } - pkcs7->pkcs7 = ASN1_TYPE_EMPTY; - - result = asn1_create_element(_gnutls_get_pkix(), - "PKIX1.ContentInfo", - &pkcs7->pkcs7); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } result = asn1_der_decoding(&pkcs7->pkcs7, _data.data, _data.size, NULL); if (result != ASN1_SUCCESS) { @@ -127,8 +126,6 @@ int gnutls_pkcs7_import(gnutls_pkcs7 pkcs7, const gnutls_datum * data, return 0; cleanup: - if (pkcs7->pkcs7) - asn1_delete_structure(&pkcs7->pkcs7); if (need_free) _gnutls_free_datum( &_data); return result; } diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c index 2e6f6880c1..ad3971d236 100644 --- a/lib/x509/privkey.c +++ b/lib/x509/privkey.c @@ -255,8 +255,8 @@ static ASN1_TYPE decode_dsa_key( const gnutls_datum* raw_key, } -#define PEM_KEY_DSA "DSA PRIVATE" -#define PEM_KEY_RSA "RSA PRIVATE" +#define PEM_KEY_DSA "DSA PRIVATE KEY" +#define PEM_KEY_RSA "RSA PRIVATE KEY" /** * gnutls_x509_privkey_import - This function will import a DER or PEM encoded Certificate @@ -478,67 +478,16 @@ int gnutls_x509_privkey_get_pk_algorithm( gnutls_x509_privkey key) int gnutls_x509_privkey_export( gnutls_x509_privkey key, gnutls_x509_crt_fmt format, unsigned char* output_data, int* output_data_size) { - int result; - - if (format == GNUTLS_X509_FMT_DER) { - if ((result=asn1_der_coding( key->key, "", output_data, output_data_size, NULL)) != ASN1_SUCCESS) { - gnutls_assert(); - - if (result == ASN1_MEM_ERROR) - return GNUTLS_E_SHORT_MEMORY_BUFFER; - - return _gnutls_asn2err(result); - } - - } else { /* PEM */ - opaque tmp[5*1024]; - opaque *out; - int len; - char * msg; - - len = sizeof(tmp) - 1; - if ((result=asn1_der_coding( key->key, "", tmp, &len, NULL)) != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - - if (key->pk_algorithm == GNUTLS_PK_RSA) - msg = "RSA PRIVATE KEY"; - else if (key->pk_algorithm == GNUTLS_PK_DSA) - msg = "DSA PRIVATE KEY"; - else msg = NULL; - - result = _gnutls_fbase64_encode( msg, - tmp, len, &out); - - if (result < 0) { - gnutls_assert(); - return result; - } - - if (result == 0) { /* oooops */ - gnutls_assert(); - return GNUTLS_E_INTERNAL_ERROR; - } - - if (result + 1 > *output_data_size) { - gnutls_assert(); - gnutls_free(out); - *output_data_size = result; - return GNUTLS_E_SHORT_MEMORY_BUFFER; - } - - *output_data_size = result; - - if (output_data) { - memcpy( output_data, out, result); - output_data[result] = 0; - } - gnutls_free( out); + char * msg; - } - - return 0; + if (key->pk_algorithm == GNUTLS_PK_RSA) + msg = PEM_KEY_RSA; + else if (key->pk_algorithm == GNUTLS_PK_DSA) + msg = PEM_KEY_DSA; + else msg = NULL; + + return _gnutls_x509_export_int( key->key, format, msg, *output_data_size, + output_data, output_data_size); } /** diff --git a/lib/x509/sign.c b/lib/x509/sign.c new file mode 100644 index 0000000000..78af41144c --- /dev/null +++ b/lib/x509/sign.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2003 Nikos Mavroyanopoulos <nmav@hellug.gr> + * + * This file is part of GNUTLS. + * + * The GNUTLS library 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* All functions which relate to X.509 certificate signing stuff are + * included here + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <gnutls_cert.h> +#include <libtasn1.h> +#include <gnutls_global.h> +#include <gnutls_num.h> /* GMAX */ +#include <gnutls_sig.h> +#include <gnutls_str.h> +#include <gnutls_datum.h> +#include <dn.h> +#include <x509.h> +#include <mpi.h> +#include <sign.h> +#include <verify.h> + +/* 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_mac_algorithm hash, + const gnutls_datum* digest, gnutls_datum *info) +{ +ASN1_TYPE dinfo = ASN1_TYPE_EMPTY; +int result; +char* algo; + + switch(hash) { + case GNUTLS_MAC_MD5: + algo = OID_MD5; + break; + case GNUTLS_MAC_MD2: + algo = OID_MD2; + break; + case GNUTLS_MAC_SHA: + algo = OID_SHA1; + break; + default: + return GNUTLS_E_UNIMPLEMENTED_FEATURE; + } + + 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); + } + + result = + asn1_write_value( dinfo, "digest", digest->data, digest->size); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + asn1_delete_structure(&dinfo); + return _gnutls_asn2err(result); + } + + info->size = 128; + info->data = gnutls_malloc( info->size); + if (info->data == NULL) { + gnutls_assert(); + asn1_delete_structure(&dinfo); + return GNUTLS_E_MEMORY_ERROR; + } + + result = asn1_der_coding( dinfo, "", info->data, &info->size, NULL); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + asn1_delete_structure(&dinfo); + return _gnutls_asn2err(result); + } + + asn1_delete_structure(&dinfo); + + return 0; +} + +/* if hash==MD5 then we do RSA-MD5 + * if hash==SHA then we do RSA-SHA + * params[0] is modulus + * params[1] is public key + */ +static int +_pkcs1_rsa_sign( gnutls_mac_algorithm hash, const gnutls_datum* text, + GNUTLS_MPI *params, int params_len, gnutls_datum* signature) +{ + int ret; + opaque _digest[MAX_HASH_SIZE]; + GNUTLS_HASH_HANDLE hd; + gnutls_datum digest, info; + + hd = _gnutls_hash_init( hash); + if (hd == NULL) { + gnutls_assert(); + return GNUTLS_E_HASH_FAILED; + } + + _gnutls_hash( hd, text->data, text->size); + _gnutls_hash_deinit( hd, _digest); + + digest.data = _digest; + digest.size = _gnutls_hash_get_algo_len(hash); + + /* Encode the digest as a DigestInfo + */ + if ( (ret = encode_ber_digest_info( hash, &digest, &info)) != 0) { + gnutls_assert(); + return ret; + } + + if ( (ret=_gnutls_sign( GNUTLS_PK_RSA, params, params_len, &info, signature)) < 0) { + gnutls_assert(); + _gnutls_free_datum( &info); + return ret; + } + + _gnutls_free_datum( &info); + + return 0; +} + +/* Signs the given data using the parameters from the signer's + * private key. + * + * returns 0 on success. + * + * 'tbs' is the data to be signed + * 'signature' will hold the signature! + * 'hash' is only used in PKCS1 RSA signing. + */ +int _gnutls_x509_sign( const gnutls_datum* tbs, gnutls_mac_algorithm hash, + gnutls_x509_privkey signer, gnutls_datum* signature) +{ +int ret; + + switch( signer->pk_algorithm) + { + case GNUTLS_PK_RSA: + + ret = _pkcs1_rsa_sign( hash, tbs, signer->params, signer->params_size, + signature); + if (ret < 0) { + gnutls_assert(); + return ret; + } + return 0; + break; + + case GNUTLS_PK_DSA: + ret = _gnutls_dsa_sign( signature, tbs, signer->params, signer->params_size); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + return 0; + break; + default: + gnutls_assert(); + return GNUTLS_E_INTERNAL_ERROR; + } + +} + diff --git a/lib/x509/sign.h b/lib/x509/sign.h new file mode 100644 index 0000000000..6c5df85d5d --- /dev/null +++ b/lib/x509/sign.h @@ -0,0 +1,2 @@ +int _gnutls_x509_sign( const gnutls_datum* tbs, gnutls_mac_algorithm hash, + gnutls_x509_privkey signer, gnutls_datum* signature); diff --git a/lib/x509/verify.c b/lib/x509/verify.c index 536025abdc..b2f348b668 100644 --- a/lib/x509/verify.c +++ b/lib/x509/verify.c @@ -357,15 +357,11 @@ unsigned int _gnutls_x509_verify_certificate(gnutls_x509_crt * certificate_list, } -#define OID_SHA1 "1.3.14.3.2.26" -#define OID_MD5 "1.2.840.113549.2.5" -#define OID_MD2 "1.2.840.113549.2.2" - /* Reads the digest information. * we use DER here, although we should use BER. It works fine * anyway. */ -static int _gnutls_get_ber_digest_info( const gnutls_datum *info, gnutls_mac_algorithm *hash, +static int decode_ber_digest_info( const gnutls_datum *info, gnutls_mac_algorithm *hash, opaque* digest, int *digest_size) { ASN1_TYPE dinfo = ASN1_TYPE_EMPTY; @@ -442,7 +438,7 @@ _pkcs1_rsa_verify_sig( const gnutls_datum* text, const gnutls_datum* signature, int digest_size; GNUTLS_HASH_HANDLE hd; gnutls_datum decrypted; - + if ( (ret=_gnutls_pkcs1_rsa_decrypt( &decrypted, *signature, params, params_len, 1)) < 0) { gnutls_assert(); return ret; @@ -452,7 +448,7 @@ _pkcs1_rsa_verify_sig( const gnutls_datum* text, const gnutls_datum* signature, */ digest_size = sizeof(digest); - if ( (ret = _gnutls_get_ber_digest_info( &decrypted, &hash, digest, &digest_size)) != 0) { + if ( (ret = decode_ber_digest_info( &decrypted, &hash, digest, &digest_size)) != 0) { gnutls_assert(); _gnutls_free_datum( &decrypted); return ret; @@ -466,6 +462,11 @@ _pkcs1_rsa_verify_sig( const gnutls_datum* text, const gnutls_datum* signature, } hd = _gnutls_hash_init( hash); + if (hd == NULL) { + gnutls_assert(); + return GNUTLS_E_HASH_FAILED; + } + _gnutls_hash( hd, text->data, text->size); _gnutls_hash_deinit( hd, md); diff --git a/lib/x509/x509.c b/lib/x509/x509.c index 4c71a4cc68..f65ed0faa4 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -19,6 +19,9 @@ * */ +/* Functions on X.509 Certificate parsing + */ + #include <gnutls_int.h> #include <gnutls_datum.h> #include <gnutls_global.h> @@ -46,7 +49,13 @@ int gnutls_x509_crt_init(gnutls_x509_crt * cert) *cert = gnutls_calloc( 1, sizeof(gnutls_x509_crt_int)); if (*cert) { - (*cert)->cert = ASN1_TYPE_EMPTY; + int result = asn1_create_element(_gnutls_get_pkix(), + "PKIX1.Certificate", + &(*cert)->cert); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } return 0; /* success */ } return GNUTLS_E_MEMORY_ERROR; @@ -79,7 +88,7 @@ void gnutls_x509_crt_deinit(gnutls_x509_crt cert) * to the native gnutls_x509_crt format. The output will be stored in 'cert'. * * If the Certificate is PEM encoded it should have a header of "X509 CERTIFICATE", or - * "CERTIFICATE" and must be a null terminated string. + * "CERTIFICATE". * * Returns 0 on success. * @@ -118,16 +127,6 @@ int gnutls_x509_crt_import(gnutls_x509_crt cert, const gnutls_datum * data, need_free = 1; } - cert->cert = ASN1_TYPE_EMPTY; - - result = asn1_create_element(_gnutls_get_pkix(), - "PKIX1.Certificate", - &cert->cert); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - result = asn1_der_decoding(&cert->cert, _data.data, _data.size, NULL); if (result != ASN1_SUCCESS) { result = _gnutls_asn2err(result); @@ -205,8 +204,6 @@ int gnutls_x509_crt_import(gnutls_x509_crt cert, const gnutls_datum * data, return 0; cleanup: - if (cert->cert) - asn1_delete_structure(&cert->cert); _gnutls_free_datum(&cert->signed_data); _gnutls_free_datum(&cert->signature); if (need_free) _gnutls_free_datum( &_data); @@ -1003,3 +1000,76 @@ gnutls_datum tmp; return gnutls_fingerprint( algo, &tmp, buf, sizeof_buf); } + + +/* A generic export function. Will export the given ASN.1 encoded data + * to PEM or DER raw data. + */ +int _gnutls_x509_export_int( ASN1_TYPE asn1_data, + gnutls_x509_crt_fmt format, char* pem_header, + int tmp_buf_size, unsigned char* output_data, int* output_data_size) +{ + int result; + + if (format == GNUTLS_X509_FMT_DER) { + if ((result=asn1_der_coding( asn1_data, "", output_data, output_data_size, NULL)) != ASN1_SUCCESS) { + gnutls_assert(); + + if (result == ASN1_MEM_ERROR) + return GNUTLS_E_SHORT_MEMORY_BUFFER; + + return _gnutls_asn2err(result); + } + + } else { /* PEM */ + opaque *tmp; + opaque *out; + int len; + + tmp = gnutls_alloca( tmp_buf_size); + if (tmp == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + len = tmp_buf_size - 1; + if ((result=asn1_der_coding( asn1_data, "", tmp, &len, NULL)) != ASN1_SUCCESS) { + gnutls_assert(); + gnutls_afree(tmp); + return _gnutls_asn2err(result); + } + + result = _gnutls_fbase64_encode( pem_header, + tmp, len, &out); + + gnutls_afree(tmp); + + if (result < 0) { + gnutls_assert(); + return result; + } + + if (result == 0) { /* oooops */ + gnutls_assert(); + return GNUTLS_E_INTERNAL_ERROR; + } + + if (result + 1 > *output_data_size) { + gnutls_assert(); + gnutls_free(out); + *output_data_size = result; + return GNUTLS_E_SHORT_MEMORY_BUFFER; + } + + *output_data_size = result; + + if (output_data) { + memcpy( output_data, out, result); + output_data[result] = 0; + } + gnutls_free( out); + + } + + return 0; +} diff --git a/lib/x509/x509.h b/lib/x509/x509.h index 4a2fc7818f..4465e01a1a 100644 --- a/lib/x509/x509.h +++ b/lib/x509/x509.h @@ -1,6 +1,10 @@ #ifndef X509_H # define X509_H +#define OID_SHA1 "1.3.14.3.2.26" +#define OID_MD5 "1.2.840.113549.2.5" +#define OID_MD2 "1.2.840.113549.2.2" + typedef struct gnutls_x509_crl_int { ASN1_TYPE crl; gnutls_datum signed_data; /* Holds the signed data of the CRL. @@ -126,5 +130,8 @@ int gnutls_x509_privkey_export_rsa_raw(gnutls_x509_privkey key, gnutls_datum *d, gnutls_datum *p, gnutls_datum* q, gnutls_datum* u); +int _gnutls_x509_export_int( ASN1_TYPE asn1_data, + gnutls_x509_crt_fmt format, char* pem_header, + int tmp_buf_size, unsigned char* output_data, int* output_data_size); #endif |