diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2002-02-01 11:14:47 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2002-02-01 11:14:47 +0000 |
commit | 4eb7eee2eebdf38466a955b73e122933422491bf (patch) | |
tree | 9719b14062087936fd518b56b7afbe64d382f969 /lib/gnutls_cert.c | |
parent | 0a048d3c44bb23f6856587779c5ae0435d54f388 (diff) | |
download | gnutls-4eb7eee2eebdf38466a955b73e122933422491bf.tar.gz |
Several changes in certificate and key handling.
* gnutls_certificate_allocate_sc() does not require the ncerts argument
Diffstat (limited to 'lib/gnutls_cert.c')
-rw-r--r-- | lib/gnutls_cert.c | 1212 |
1 files changed, 49 insertions, 1163 deletions
diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c index 4475f102bb..717b9d1a72 100644 --- a/lib/gnutls_cert.c +++ b/lib/gnutls_cert.c @@ -20,20 +20,22 @@ #include <gnutls_int.h> #include <gnutls_errors.h> -#include <x509_b64.h> #include <auth_cert.h> #include <gnutls_cert.h> #include <x509_asn1.h> #include <x509_der.h> #include <gnutls_datum.h> #include <gnutls_gcry.h> -#include <gnutls_privkey.h> #include <gnutls_global.h> #include <x509_verify.h> +#include <gnutls_privkey.h> #include <x509_extensions.h> #include <gnutls_algorithms.h> #include <gnutls_dh.h> #include <gnutls_str.h> +#include <gnutls_state.h> +#include <gnutls_auth_int.h> +#include <gnutls_x509.h> /* KX mappings to PK algorithms */ typedef struct { @@ -135,1184 +137,25 @@ void gnutls_certificate_free_sc(GNUTLS_CERTIFICATE_CREDENTIALS sc) gnutls_free(sc); } -#define MAX_FILE_SIZE 100*1024 -#define CERT_SEP "-----BEGIN" - -/* Reads a base64 encoded certificate from memory - */ -static int read_cert_mem(GNUTLS_CERTIFICATE_CREDENTIALS res, const char *cert, int cert_size) -{ - int siz, i, siz2; - opaque *b64; - const char *ptr; - gnutls_datum tmp; - int ret; - - ptr = cert; - siz = cert_size; - i = 1; - - res->cert_list[res->ncerts] = NULL; - - do { - siz2 = _gnutls_fbase64_decode(ptr, siz, &b64); - siz -= siz2; /* FIXME: this is not enough - */ - - if (siz2 < 0) { - gnutls_assert(); - gnutls_free(b64); - return GNUTLS_E_PARSING_ERROR; - } - - - res->cert_list[res->ncerts] = - (gnutls_cert *) gnutls_realloc(res-> - cert_list[res->ncerts], - i * - sizeof(gnutls_cert)); - - if (res->cert_list[res->ncerts] == NULL) { - gnutls_assert(); - gnutls_free(b64); - return GNUTLS_E_MEMORY_ERROR; - } - /* set defaults to zero - */ - memset(&res->cert_list[res->ncerts][i - 1], 0, - sizeof(gnutls_cert)); - - tmp.data = b64; - tmp.size = siz2; - - if ((ret = - _gnutls_x509_cert2gnutls_cert(&res-> - cert_list[res->ncerts][i - 1], - tmp)) < 0) { - gnutls_free(b64); - gnutls_assert(); - return ret; - } - gnutls_free(b64); - - /* now we move ptr after the pem header */ - ptr = strstr(ptr, CERT_SEP); - if (ptr!=NULL) - ptr++; - - i++; - } while ((ptr = strstr(ptr, CERT_SEP)) != NULL); - - res->cert_list_length[res->ncerts] = i - 1; - - /* WE DO NOT CATCH OVERRUNS in gnutls_x509pki_set_key(). - * This function should be called as many times as specified - * in certificate_allocate_sc(). - */ - res->ncerts++; - - return 0; -} - -/* Reads a base64 encoded CA list from memory - * This is to be called once. - */ -static int read_ca_mem(GNUTLS_CERTIFICATE_CREDENTIALS res, const char *ca, int ca_size) -{ - int siz, siz2, i; - opaque *b64; - const char *ptr; - int ret; - gnutls_datum tmp; - - siz = ca_size; - - ptr = ca; - - i = res->x509_ncas + 1; - - do { - siz2 = _gnutls_fbase64_decode(ptr, siz, &b64); - siz -= siz2; /* FIXME: this is not enough - */ - - if (siz2 < 0) { - gnutls_assert(); - gnutls_free(b64); - return GNUTLS_E_PARSING_ERROR; - } - - res->x509_ca_list = - (gnutls_cert *) gnutls_realloc(res->x509_ca_list, - i * - sizeof(gnutls_cert)); - if (res->x509_ca_list == NULL) { - gnutls_assert(); - gnutls_free(b64); - return GNUTLS_E_MEMORY_ERROR; - } - memset(&res->x509_ca_list[i - 1], 0, sizeof(gnutls_cert)); - - tmp.data = b64; - tmp.size = siz2; - - if ((ret = - _gnutls_x509_cert2gnutls_cert(&res->x509_ca_list[i - 1], - tmp)) < 0) { - gnutls_assert(); - gnutls_free(b64); - return ret; - } - gnutls_free(b64); - - /* now we move ptr after the pem header */ - ptr = strstr(ptr, CERT_SEP); - if (ptr!=NULL) - ptr++; - - i++; - } while ((ptr = strstr(ptr, CERT_SEP)) != NULL); - - res->x509_ncas = i - 1; - - - - return 0; -} - - -/* Reads a PEM encoded PKCS-1 RSA private key from memory - * 2002-01-26: Added ability to read DSA keys. - */ -static int read_key_mem(GNUTLS_CERTIFICATE_CREDENTIALS res, const char *key, int key_size) -{ - int siz, ret; - opaque *b64; - gnutls_datum tmp; - PKAlgorithm pk; - - /* read PKCS-1 private key */ - siz = key_size; - - - /* If we find the "DSA PRIVATE" string in the - * pem encoded certificate then it's a DSA key. - */ - if (strstr( key, "DSA PRIVATE")!=NULL) - pk = GNUTLS_PK_DSA; - else - pk = GNUTLS_PK_RSA; - - siz = _gnutls_fbase64_decode(key, siz, &b64); - - if (siz < 0) { - gnutls_assert(); - gnutls_free(b64); - return GNUTLS_E_PARSING_ERROR; - } - - tmp.data = b64; - tmp.size = siz; - - switch (pk) { /* decode the key */ - case GNUTLS_PK_RSA: - if ((ret = - _gnutls_PKCS1key2gnutlsKey(&res->pkey[res->ncerts], - tmp)) < 0) { - gnutls_assert(); - gnutls_free(b64); - return ret; - } - break; - case GNUTLS_PK_DSA: - if ((ret = - _gnutls_DSAkey2gnutlsKey(&res->pkey[res->ncerts], - tmp)) < 0) { - gnutls_assert(); - gnutls_free(b64); - return ret; - } - break; - } - gnutls_free(b64); - - return 0; -} - -/* Reads a base64 encoded certificate file - */ -static int read_cert_file(GNUTLS_CERTIFICATE_CREDENTIALS res, char *certfile) -{ - int siz; - char x[MAX_FILE_SIZE]; - FILE *fd1; - - fd1 = fopen(certfile, "r"); - if (fd1 == NULL) - return GNUTLS_E_UNKNOWN_ERROR; - - siz = fread(x, 1, sizeof(x), fd1); - fclose(fd1); - - x[siz-1] = 0; - - return read_cert_mem( res, x, siz); - -} - -/* Reads a base64 encoded CA file (file contains multiple certificate - * authorities). This is to be called once. - */ -static int read_ca_file(GNUTLS_CERTIFICATE_CREDENTIALS res, char *cafile) -{ - int siz; - char x[MAX_FILE_SIZE]; - FILE *fd1; - - fd1 = fopen(cafile, "r"); - if (fd1 == NULL) { - gnutls_assert(); - return GNUTLS_E_UNKNOWN_ERROR; - } - - siz = fread(x, 1, sizeof(x), fd1); - fclose(fd1); - - x[siz-1] = 0; - - return read_ca_mem( res, x, siz); -} - - -/* Reads a PEM encoded PKCS-1 RSA private key file - */ -static int read_key_file(GNUTLS_CERTIFICATE_CREDENTIALS res, char *keyfile) -{ - int siz; - char x[MAX_FILE_SIZE]; - FILE *fd2; - - fd2 = fopen(keyfile, "r"); - if (fd2 == NULL) - return GNUTLS_E_UNKNOWN_ERROR; - - siz = fread(x, 1, sizeof(x), fd2); - fclose(fd2); - - x[siz-1] = 0; - - return read_key_mem( res, x, siz); -} /** * gnutls_certificate_allocate_sc - Used to allocate an x509 SERVER CREDENTIALS structure * @res: is a pointer to an &GNUTLS_CERTIFICATE_CREDENTIALS structure. - * @ncerts: this is the number of certificate/private key pair you're going to use. - * This should be 1 in common sites. * * This structure is complex enough to manipulate directly thus * this helper function is provided in order to allocate * the structure. **/ -int gnutls_certificate_allocate_sc(GNUTLS_CERTIFICATE_CREDENTIALS * res, int ncerts) +int gnutls_certificate_allocate_sc(GNUTLS_CERTIFICATE_CREDENTIALS * res) { -#warning FIX NCERTS *res = gnutls_calloc(1, sizeof(CERTIFICATE_CREDENTIALS_INT)); if (*res == NULL) return GNUTLS_E_MEMORY_ERROR; - - (*res)->ncerts = 0; /* this is right - set_key() increments it */ - - if (ncerts > 0) { - (*res)->cert_list = - (gnutls_cert **) gnutls_malloc(ncerts * - sizeof(gnutls_cert *)); - - if ((*res)->cert_list == NULL) { - gnutls_free(*res); - return GNUTLS_E_MEMORY_ERROR; - } - - (*res)->cert_list_length = - (int *) gnutls_malloc(ncerts * sizeof(int *)); - if ((*res)->cert_list_length == NULL) { - gnutls_free(*res); - gnutls_free((*res)->cert_list); - return GNUTLS_E_MEMORY_ERROR; - } - - (*res)->pkey = - gnutls_malloc(ncerts * sizeof(gnutls_private_key)); - if ((*res)->pkey == NULL) { - gnutls_free(*res); - gnutls_free((*res)->cert_list); - gnutls_free((*res)->cert_list_length); - return GNUTLS_E_MEMORY_ERROR; - } - - } - return 0; } -/* returns error if the certificate has different algorithm than - * the given key parameters. - */ -static int _gnutls_check_key_cert_match( GNUTLS_CERTIFICATE_CREDENTIALS res) { - if (res->pkey->pk_algorithm != res->cert_list[0]->subject_pk_algorithm) { - gnutls_assert(); - return GNUTLS_E_CERTIFICATE_KEY_MISMATCH; - } - return 0; -} - - -/** - * gnutls_x509pki_set_key_file - Used to set keys in a GNUTLS_CERTIFICATE_CREDENTIALS structure - * @res: is an &GNUTLS_CERTIFICATE_CREDENTIALS structure. - * @CERTFILE: is a PEM encoded file containing the certificate list (path) for - * the specified private key - * @KEYFILE: is a PEM encoded file containing a private key - * - * This function sets a certificate/private key pair in the - * GNUTLS_CERTIFICATE_CREDENTIALS structure. This function may be called - * more than once (in case multiple keys/certificates exist for the - * server). - * - * Currently only PKCS-1 PEM encoded RSA and DSA private keys are accepted by - * this function. - * - **/ -int gnutls_x509pki_set_key_file(GNUTLS_CERTIFICATE_CREDENTIALS res, char *CERTFILE, - char *KEYFILE) -{ - int ret; - - /* this should be first - */ - if ((ret = read_key_file(res, KEYFILE)) < 0) - return ret; - - if ((ret = read_cert_file(res, CERTFILE)) < 0) - return ret; - - if ((ret=_gnutls_check_key_cert_match( res)) < 0) { - gnutls_assert(); - return ret; - } - - return 0; -} - -static int generate_rdn_seq( GNUTLS_CERTIFICATE_CREDENTIALS res) { -gnutls_datum tmp; -int ret, size, i; -opaque *pdata; - - /* Generate the RDN sequence - * This will be sent to clients when a certificate - * request message is sent. - */ - - /* FIXME: in case of a client it is not needed - * to do that. This would save time and memory. - * However we don't have that information available - * here. - */ - - size = 0; - for (i = 0; i < res->x509_ncas; i++) { - if ((ret = _gnutls_find_dn(&tmp, &res->x509_ca_list[i])) < 0) { - gnutls_assert(); - return ret; - } - size += (2 + tmp.size); - } - - if (res->x509_rdn_sequence.data != NULL) - gnutls_free( res->x509_rdn_sequence.data); - - res->x509_rdn_sequence.data = gnutls_malloc(size); - if (res->x509_rdn_sequence.data == NULL) { - gnutls_assert(); - return GNUTLS_E_MEMORY_ERROR; - } - res->x509_rdn_sequence.size = size; - - pdata = res->x509_rdn_sequence.data; - - for (i = 0; i < res->x509_ncas; i++) { - if ((ret = _gnutls_find_dn(&tmp, &res->x509_ca_list[i])) < 0) { - gnutls_free(res->x509_rdn_sequence.data); - res->x509_rdn_sequence.size = 0; - res->x509_rdn_sequence.data = NULL; - gnutls_assert(); - return ret; - } - WRITEdatum16(pdata, tmp); - pdata += (2 + tmp.size); - } - - return 0; -} - -/** - * gnutls_x509pki_set_trust_mem - Used to add trusted CAs in a GNUTLS_CERTIFICATE_CREDENTIALS structure - * @res: is an &GNUTLS_CERTIFICATE_CREDENTIALS structure. - * @CA: is a PEM encoded list of trusted CAs - * @CRL: is a PEM encoded list of CRLs (ignored for now) - * - * This function adds the trusted CAs in order to verify client - * certificates. This function may be called multiple times. - * - **/ -int gnutls_x509pki_set_trust_mem(GNUTLS_CERTIFICATE_CREDENTIALS res, const gnutls_datum *CA, - const gnutls_datum *CRL) -{ - int ret; - - if ((ret = read_ca_mem(res, CA->data, CA->size)) < 0) - return ret; - - if ((ret = generate_rdn_seq(res)) < 0) - return ret; - - return 0; -} - -/** - * gnutls_x509pki_set_trust_file - Used to add trusted CAs in a GNUTLS_CERTIFICATE_CREDENTIALS structure - * @res: is an &GNUTLS_CERTIFICATE_CREDENTIALS structure. - * @CAFILE: is a PEM encoded file containing trusted CAs - * @CRLFILE: is a PEM encoded file containing CRLs (ignored for now) - * - * This function sets the trusted CAs in order to verify client - * certificates. This function may be called multiple times. - * - **/ -int gnutls_x509pki_set_trust_file(GNUTLS_CERTIFICATE_CREDENTIALS res, char *CAFILE, - char *CRLFILE) -{ - int ret; - - if ((ret = read_ca_file(res, CAFILE)) < 0) - return ret; - - if ((ret = generate_rdn_seq(res)) < 0) - return ret; - - return 0; -} - - -/** - * gnutls_x509pki_set_key_mem - Used to set keys in a GNUTLS_CERTIFICATE_CREDENTIALS structure - * @res: is an &GNUTLS_CERTIFICATE_CREDENTIALS structure. - * @CERT: contains a PEM encoded certificate list (path) for - * the specified private key - * @KEY: is a PEM encoded private key - * - * This function sets a certificate/private key pair in the - * GNUTLS_CERTIFICATE_CREDENTIALS structure. This function may be called - * more than once (in case multiple keys/certificates exist for the - * server). - * - * Currently only PKCS-1 PEM encoded RSA private keys are accepted by - * this function. - * - **/ -int gnutls_x509pki_set_key_mem(GNUTLS_CERTIFICATE_CREDENTIALS res, const gnutls_datum* CERT, - const gnutls_datum* KEY) -{ - int ret; - - /* this should be first - */ - if ((ret = read_key_mem( res, KEY->data, KEY->size)) < 0) - return ret; - - if ((ret = read_cert_mem( res, CERT->data, CERT->size)) < 0) - return ret; - - if ((ret=_gnutls_check_key_cert_match( res)) < 0) { - gnutls_assert(); - return ret; - } - - return 0; -} - - -static int _read_rsa_params(opaque * der, int dersize, MPI * params) -{ - opaque str[MAX_PARAMETER_SIZE]; - int result; - node_asn *spk; - - if (asn1_create_structure - (_gnutls_get_gnutls_asn(), "GNUTLS.RSAPublicKey", &spk, - "rsa_public_key") != ASN_OK) { - gnutls_assert(); - return GNUTLS_E_ASN1_ERROR; - } - - result = asn1_get_der(spk, der, dersize); - - if (result != ASN_OK) { - gnutls_assert(); - asn1_delete_structure(spk); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - - if ( (result=_gnutls_x509_read_int( spk, "rsa_public_key.modulus", - str, sizeof(str)-1, ¶ms[0])) < 0) { - gnutls_assert(); - asn1_delete_structure(spk); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - if ( (result=_gnutls_x509_read_int( spk, "rsa_public_key.publicExponent", - str, sizeof(str)-1, ¶ms[1])) < 0) { - gnutls_assert(); - _gnutls_mpi_release(¶ms[0]); - asn1_delete_structure(spk); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - asn1_delete_structure(spk); - - return 0; - -} - - -/* reads p,q and g - * from the certificate - * params[0-2] - */ -static int _read_dsa_params(opaque * der, int dersize, MPI * params) -{ - opaque str[MAX_PARAMETER_SIZE]; - int result; - node_asn *spk; - - if (asn1_create_structure - (_gnutls_get_pkix(), "PKIX1Implicit88.Dss-Parms", &spk, - "dsa_parms") != ASN_OK) { - gnutls_assert(); - return GNUTLS_E_ASN1_ERROR; - } - - result = asn1_get_der(spk, der, dersize); - - if (result != ASN_OK) { - gnutls_assert(); - asn1_delete_structure(spk); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - /* FIXME: If the parameters are not included in the certificate - * then the issuer's parameters should be used. - */ - - /* Read p */ - - if ( (result=_gnutls_x509_read_int( spk, "dsa_parms.p", str, sizeof(str)-1, ¶ms[0])) < 0) { - gnutls_assert(); - asn1_delete_structure(spk); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - /* Read q */ - - if ( (result=_gnutls_x509_read_int( spk, "dsa_parms.q", str, sizeof(str)-1, ¶ms[1])) < 0) { - gnutls_assert(); - asn1_delete_structure(spk); - _gnutls_mpi_release(¶ms[0]); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - /* Read g */ - - if ( (result=_gnutls_x509_read_int( spk, "dsa_parms.g", str, sizeof(str)-1, ¶ms[2])) < 0) { - gnutls_assert(); - asn1_delete_structure(spk); - _gnutls_mpi_release(¶ms[0]); - _gnutls_mpi_release(¶ms[1]); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - asn1_delete_structure(spk); - - return 0; - -} - -/* reads DSA's Y - * from the certificate - * params[3] - */ -static int _read_dsa_pubkey(opaque * der, int dersize, MPI * params) -{ - opaque str[MAX_PARAMETER_SIZE]; - int result; - node_asn *spk; - - if ( (result=asn1_create_structure - (_gnutls_get_gnutls_asn(), "GNUTLS.DSAPublicKey", &spk, - "dsa_public_key")) != ASN_OK) { - gnutls_assert(); - return GNUTLS_E_ASN1_ERROR; - } - - result = asn1_get_der(spk, der, dersize); - - if (result != ASN_OK) { - gnutls_assert(); - asn1_delete_structure(spk); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - /* Read p */ - - if ( (result=_gnutls_x509_read_int( spk, "dsa_public_key", str, sizeof(str)-1, ¶ms[3])) < 0) { - gnutls_assert(); - asn1_delete_structure(spk); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - asn1_delete_structure(spk); - - return 0; - -} - - -#define _READ(a, aa, b, c, d, e, res, f) \ - result = _IREAD(a, aa, sizeof(aa), b, c, d, e, res, sizeof(res)-1, f); \ - if (result<0) return result; \ - if (result==1) continue - - -int _IREAD(node_asn * rasn, char *name3, int name3_size, char *rstr, char *OID, - char *ANAME, char *TYPE, char *res, int res_size, int CHOICE) -{ - char name2[256]; - int result, len; - char str[1024]; - node_asn *tmpasn; - - if (strcmp(rstr, OID) == 0) { - - _gnutls_str_cpy(str, sizeof(str), "PKIX1Implicit88."); - _gnutls_str_cat(str, sizeof(str), ANAME); - _gnutls_str_cpy(name2, sizeof(name2), "temp-structure-"); - _gnutls_str_cat(name2, sizeof(name2), TYPE); - - if ((result = - asn1_create_structure(_gnutls_get_pkix(), str, - &tmpasn, name2)) != ASN_OK) { - gnutls_assert(); - return GNUTLS_E_ASN1_ERROR; - } - - len = sizeof(str) -1; - if ((result = - asn1_read_value(rasn, name3, str, &len)) != ASN_OK) { - asn1_delete_structure(tmpasn); - return 1; - } - - if ((result = asn1_get_der(tmpasn, str, len)) != ASN_OK) { - asn1_delete_structure(tmpasn); - return 1; - } - _gnutls_str_cpy(name3, name3_size, name2); - - len = sizeof(str) - 1; - if ((result = asn1_read_value(tmpasn, name3, str, &len)) != ASN_OK) { /* CHOICE */ - asn1_delete_structure(tmpasn); - return 1; - } - - if (CHOICE == 0) { - str[len] = 0; - /* strlen(str) < res_size, checked above */ - _gnutls_str_cpy(res, res_size, str); - - } else { /* CHOICE */ - str[len] = 0; - _gnutls_str_cat(name3, name3_size, "."); - _gnutls_str_cat(name3, name3_size, str); - len = sizeof(str) - 1; - - if ((result = - asn1_read_value(tmpasn, name3, str, - &len)) != ASN_OK) { - asn1_delete_structure(tmpasn); - return 1; - } - str[len] = 0; - if ( len < res_size) - _gnutls_str_cpy(res, res_size, str); - } - asn1_delete_structure(tmpasn); - - } - return 0; -} - -/* this function will convert up to 3 digit - * numbers to characters. - */ -void _gnutls_int2str(int k, char *data) -{ - if (k > 999) - data[0] = 0; - else - sprintf(data, "%d", k); -} - -/* This function will attempt to read a Name - * ASN.1 structure. (Taken from Fabio's samples!) - * - * FIXME: These functions need carefull auditing - * (they're complex enough) - * --nmav - */ -int _gnutls_get_name_type(node_asn * rasn, char *root, gnutls_DN * dn) -{ - int k, k2, result, len; - char name[128], str[1024], name2[128], counter[MAX_INT_DIGITS], - name3[128]; - - k = 0; - do { - k++; - - _gnutls_str_cpy(name, sizeof(name), root); - _gnutls_str_cat(name, sizeof(name), ".rdnSequence.?"); - _gnutls_int2str(k, counter); - _gnutls_str_cat(name, sizeof(name), counter); - - len = sizeof(str) - 1; - - result = asn1_read_value(rasn, name, str, &len); - - /* move to next - */ - if (result == ASN_ELEMENT_NOT_FOUND) - break; - if (result != ASN_VALUE_NOT_FOUND) { - gnutls_assert(); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - k2 = 0; - do { - k2++; - - _gnutls_str_cpy(name2, sizeof(name2), name); - _gnutls_str_cat(name2, sizeof(name2), ".?"); - _gnutls_int2str(k2, counter); - _gnutls_str_cat(name2, sizeof(name2), counter); - - len = sizeof(str) - 1; - result = asn1_read_value(rasn, name2, str, &len); - - if (result == ASN_ELEMENT_NOT_FOUND) - break; - if (result != ASN_VALUE_NOT_FOUND) { - gnutls_assert(); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - _gnutls_str_cpy(name3, sizeof(name3), name2); - _gnutls_str_cat(name3, sizeof(name3), ".type"); - - len = sizeof(str) - 1; - result = asn1_read_value(rasn, name3, str, &len); - - if (result == ASN_ELEMENT_NOT_FOUND) - break; - else if (result != ASN_OK) { - gnutls_assert(); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - _gnutls_str_cpy(name3, sizeof(name3), name2); - _gnutls_str_cat(name3, sizeof(name3), ".value"); - - if (result == ASN_OK) { -#ifdef DEBUG -# warning " FIX COUNTRY HERE" -#endif - _READ(rasn, name3, str, "2 5 4 6", - "X520OrganizationName", - "countryName", dn->country, 1); - _READ(rasn, name3, str, "2 5 4 10", - "X520OrganizationName", - "OrganizationName", dn->organization, - 1); - _READ(rasn, name3, str, "2 5 4 11", - "X520OrganizationalUnitName", - "OrganizationalUnitName", - dn->organizational_unit_name, 1); - _READ(rasn, name3, str, "2 5 4 3", - "X520CommonName", "CommonName", - dn->common_name, 1); - _READ(rasn, name3, str, "2 5 4 7", - "X520LocalityName", "LocalityName", - dn->locality_name, 1); - _READ(rasn, name3, str, "2 5 4 8", - "X520StateOrProvinceName", - "StateOrProvinceName", - dn->state_or_province_name, 1); - _READ(rasn, name3, str, - "1 2 840 113549 1 9 1", "Pkcs9email", - "emailAddress", dn->email, 0); - } - } while (1); - } while (1); - - if (result == ASN_ELEMENT_NOT_FOUND) - return 0; - else - return GNUTLS_E_ASN1_PARSING_ERROR; -} - - - -#define MAX_TIME 1024 -time_t _gnutls_get_time(node_asn * c2, char *root, char *when) -{ - opaque ttime[MAX_TIME]; - char name[1024]; - time_t ctime; - int len, result; - - _gnutls_str_cpy(name, sizeof(name), root); - _gnutls_str_cat(name, sizeof(name), ".tbsCertificate.validity."); - _gnutls_str_cat(name, sizeof(name), when); - - len = sizeof(ttime) - 1; - if ((result = asn1_read_value(c2, name, ttime, &len)) < 0) { - gnutls_assert(); - return (time_t) (-1); - } - - /* CHOICE */ - _gnutls_str_cpy(name, sizeof(name), root); - - if (strcmp(ttime, "GeneralizedTime") == 0) { - - _gnutls_str_cat(name, sizeof(name), ".tbsCertificate.validity."); - _gnutls_str_cat(name, sizeof(name), when); - _gnutls_str_cat(name, sizeof(name), ".generalTime"); - len = sizeof(ttime) - 1; - result = asn1_read_value(c2, name, ttime, &len); - if (result == ASN_OK) - ctime = _gnutls_generalTime2gtime(ttime); - } else { /* UTCTIME */ - - _gnutls_str_cat(name, sizeof(name), ".tbsCertificate.validity."); - _gnutls_str_cat(name, sizeof(name), when); - _gnutls_str_cat(name, sizeof(name), ".utcTime"); - len = sizeof(ttime) - 1; - result = asn1_read_value(c2, name, ttime, &len); - if (result == ASN_OK) - ctime = _gnutls_utcTime2gtime(ttime); - } - - if (result != ASN_OK) { - gnutls_assert(); - return (time_t) (-1); - } - return ctime; -} - -int _gnutls_get_version(node_asn * c2, char *root) -{ - opaque gversion[5]; - char name[1024]; - int len, result; - - _gnutls_str_cpy(name, sizeof(name), root); - _gnutls_str_cat(name, sizeof(name), ".tbsCertificate.version"); - - len = sizeof(gversion) - 1; - if ((result = asn1_read_value(c2, name, gversion, &len)) < 0) { - gnutls_assert(); - return (-1); - } - return (int) gversion[0] + 1; -} - - -/* Extracts DSA and RSA parameters from a certificate. - */ -static -int _gnutls_extract_cert_mpi_params( const char* ALGO_OID, gnutls_cert * gCert, - node_asn* c2, char* tmpstr, int tmpstr_size) { -int len, result; - - if (strcmp( ALGO_OID, "1 2 840 113549 1 1 1") == 0) { /* pkix-1 1 - RSA */ - /* params[0] is the modulus, - * params[1] is the exponent - */ - gCert->subject_pk_algorithm = GNUTLS_PK_RSA; - - len = tmpstr_size - 1; - result = - asn1_read_value - (c2, "certificate2.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", - tmpstr, &len); - - if (result != ASN_OK) { - gnutls_assert(); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - if ((sizeof(gCert->params) / sizeof(MPI)) < RSA_PARAMS) { - gnutls_assert(); - /* internal error. Increase the MPIs in params */ - return GNUTLS_E_INTERNAL; - } - - if ((result = - _read_rsa_params(tmpstr, len / 8, gCert->params)) < 0) { - gnutls_assert(); - return result; - } - - return 0; - } - - if (strcmp( ALGO_OID, "1 2 840 10040 4 1") == 0) { /* pkix-1 1 - DSA */ - /* params[0] is p, - * params[1] is q, - * params[2] is q, - * params[3] is pub. - */ - gCert->subject_pk_algorithm = GNUTLS_PK_DSA; - - len = tmpstr_size - 1; - result = - asn1_read_value - (c2, "certificate2.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", - tmpstr, &len); - - if (result != ASN_OK) { - gnutls_assert(); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - if ((sizeof(gCert->params) / sizeof(MPI)) < DSA_PARAMS) { - gnutls_assert(); - /* internal error. Increase the MPIs in params */ - return GNUTLS_E_INTERNAL; - } - - if ((result = - _read_dsa_pubkey(tmpstr, len / 8, gCert->params)) < 0) { - gnutls_assert(); - return result; - } - - /* Now read the parameters - */ - len = tmpstr_size - 1; - result = - asn1_read_value - (c2, "certificate2.tbsCertificate.subjectPublicKeyInfo.algorithm.parameters", - tmpstr, &len); - - if (result != ASN_OK) { - gnutls_assert(); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - if ((result = - _read_dsa_params(tmpstr, len, gCert->params)) < 0) { - gnutls_assert(); - return result; - } - - return 0; - } - - - - /* other types like DH - * currently not supported - */ - gnutls_assert(); - - _gnutls_log("CERT: ALGORITHM: %s\n", ALGO_OID); - - gCert->subject_pk_algorithm = GNUTLS_PK_UNKNOWN; - - return GNUTLS_E_INVALID_PARAMETERS; -} - - -#define X509_SIG_SIZE 1024 - -/* This function will convert a der certificate, to a format - * (structure) that gnutls can understand and use. Actually the - * important thing on this function is that it extracts the - * certificate's (public key) parameters. - */ -int _gnutls_x509_cert2gnutls_cert(gnutls_cert * gCert, gnutls_datum derCert) -{ - int result; - node_asn *c2; - opaque str[MAX_X509_CERT_SIZE]; - int len = sizeof(str); - - memset(gCert, 0, sizeof(gnutls_cert)); - - gCert->valid = 1; - gCert->cert_type = GNUTLS_CRT_X509; - - if (gnutls_set_datum(&gCert->raw, derCert.data, derCert.size) < 0) { - gnutls_assert(); - return GNUTLS_E_MEMORY_ERROR; - } - - if (asn1_create_structure - (_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &c2, - "certificate2") - != ASN_OK) { - gnutls_assert(); - gnutls_free_datum( &gCert->raw); - return GNUTLS_E_ASN1_ERROR; - } - - result = asn1_get_der(c2, derCert.data, derCert.size); - if (result != ASN_OK) { - /* couldn't decode DER */ - - _gnutls_log("CERT: Decoding error %d\n", result); - - gnutls_assert(); - asn1_delete_structure(c2); - gnutls_free_datum( &gCert->raw); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - len = sizeof(str) - 1; - result = - asn1_read_value - (c2, - "certificate2.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm", - str, &len); - - if (result != ASN_OK) { - gnutls_assert(); - asn1_delete_structure(c2); - gnutls_free_datum( &gCert->raw); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - if ( (result=_gnutls_extract_cert_mpi_params( str, gCert, c2, str, sizeof(str))) < 0) { - gnutls_assert(); - asn1_delete_structure(c2); - gnutls_free_datum( &gCert->raw); - return result; - } - - len = gCert->signature.size = X509_SIG_SIZE; - gCert->signature.data = gnutls_malloc( gCert->signature.size); - if (gCert->signature.data==NULL) { - gnutls_assert(); - return GNUTLS_E_MEMORY_ERROR; - } - - result = - asn1_read_value - (c2, "certificate2.signature", gCert->signature.data, &len); - - if ((len % 8) != 0) { - gnutls_assert(); - asn1_delete_structure(c2); - gnutls_free_datum( &gCert->raw); - gnutls_free_datum( &gCert->signature); - return GNUTLS_E_UNIMPLEMENTED_FEATURE; - } - - len /= 8; /* convert to bytes */ - gCert->signature.size = len; /* put the actual sig size */ - - - gCert->expiration_time = - _gnutls_get_time(c2, "certificate2", "notAfter"); - gCert->activation_time = - _gnutls_get_time(c2, "certificate2", "notBefore"); - gCert->version = _gnutls_get_version(c2, "certificate2"); - - if ((result = - _gnutls_get_ext_type(c2, - "certificate2.tbsCertificate.extensions", - gCert)) < 0) { - gnutls_assert(); - asn1_delete_structure(c2); - gnutls_free_datum( &gCert->raw); - return result; - } - - asn1_delete_structure(c2); - - - gCert->valid = 0; /* if we got until here - * the certificate is valid. - */ - - return 0; - -} - -/* Returns 0 if it's ok to use the KXAlgorithm with this cert - * (using KeyUsage field). - */ -int _gnutls_check_x509_key_usage(const gnutls_cert * cert, - KXAlgorithm alg) -{ - if (_gnutls_map_kx_get_cred(alg) == GNUTLS_CRD_CERTIFICATE) { - switch (alg) { - case GNUTLS_KX_RSA: - if (cert->keyUsage != 0) { - if (! - (cert-> - keyUsage & GNUTLS_X509KEY_KEY_ENCIPHERMENT)) - return - GNUTLS_E_X509_KEY_USAGE_VIOLATION; - else - return 0; - } - return 0; - case GNUTLS_KX_DHE_RSA: - case GNUTLS_KX_DHE_DSS: - if (cert->keyUsage != 0) { - if (! - (cert-> - keyUsage & GNUTLS_X509KEY_DIGITAL_SIGNATURE)) - return - GNUTLS_E_X509_KEY_USAGE_VIOLATION; - else - return 0; - } - return 0; - default: - gnutls_assert(); - return GNUTLS_E_X509_KEY_USAGE_VIOLATION; - } - } - return 0; -} /* returns the KX algorithms that are supported by a * certificate. (Eg a certificate with RSA params, supports @@ -1332,7 +175,16 @@ int _gnutls_cert_supported_kx(const gnutls_cert * cert, KXAlgorithm ** alg, for (kx = 0; kx < MAX_KX_ALGOS; kx++) { pk = _gnutls_map_pk_get_pk(kx); if (pk == cert->subject_pk_algorithm) { - if (_gnutls_check_x509_key_usage(cert, kx) == 0) { + if (cert->cert_type==GNUTLS_CRT_X509) { + /* then check key usage */ + if (_gnutls_check_x509_key_usage(cert, kx) == 0) { + kxlist[i] = kx; + i++; + } + } else if ( cert->cert_type==GNUTLS_CRT_OPENPGP) { + /* FIXME: something like key usage + * should be added + */ kxlist[i] = kx; i++; } @@ -1453,3 +305,37 @@ void gnutls_certificate_server_set_select_func(GNUTLS_STATE state, { state->gnutls_internals.server_cert_callback = func; } + +/** + * gnutls_certificate_verify_peers - This function returns the peer's certificate verification status + * @state: is a gnutls state + * + * This function will try to verify the peer's certificate and return it's status (TRUSTED, EXPIRED etc.). + * The return value (status) should be one of the CertificateStatus enumerated elements. + * However you must also check the peer's name in order to check if the verified certificate belongs to the + * actual peer. Returns a negative error code in case of an error, or GNUTLS_CERT_NONE if no certificate was sent. + * + **/ +int gnutls_certificate_verify_peers(GNUTLS_STATE state) +{ + CERTIFICATE_AUTH_INFO info; + + CHECK_AUTH(GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST); + + info = _gnutls_get_auth_info(state); + if (info == NULL) + return GNUTLS_E_INVALID_REQUEST; + + if (info->raw_certificate_list == NULL || info->ncerts == 0) + return GNUTLS_CERT_NONE; + + switch( gnutls_cert_type_get( state)) { + case GNUTLS_CRT_X509: + return _gnutls_x509_cert_verify_peers( state); + case GNUTLS_CRT_OPENPGP: + /* FIX THIS */ +/* return _gnutls_openpgp_cert_verify_peers( state); */ + default: + return GNUTLS_E_INVALID_REQUEST; + } +} |