diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2001-06-21 18:38:53 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2001-06-21 18:38:53 +0000 |
commit | b8851f3a04ea5e99b37ba17b507c7b1bdb5a7347 (patch) | |
tree | e3f8039aa07ec514260246c38300f84e4bbfa4f7 /lib/gnutls_cert.c | |
parent | 06ee26c4753c4e399741f1710f6f0dd526130776 (diff) | |
download | gnutls-b8851f3a04ea5e99b37ba17b507c7b1bdb5a7347.tar.gz |
Updated Ciphersuite selection algorithm.
Added internal representation of x509 structures.
Diffstat (limited to 'lib/gnutls_cert.c')
-rw-r--r-- | lib/gnutls_cert.c | 367 |
1 files changed, 356 insertions, 11 deletions
diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c index 9d7b39d00a..5d59b306f2 100644 --- a/lib/gnutls_cert.c +++ b/lib/gnutls_cert.c @@ -23,6 +23,48 @@ #include <gnutls_errors.h> #include <cert_b64.h> #include <auth_x509.h> +#include <gnutls_cert.h> +#include <cert_asn1.h> +#include <cert_der.h> +#include <gnutls_datum.h> + +/* KX mappings to PK algorithms */ +typedef struct { + KXAlgorithm kx_algorithm; + PKAlgorithm pk_algorithm; +} gnutls_pk_map; + +/* This table maps the Key exchange algorithms to + * the certificate algorithms. Eg. if we have + * RSA algorithm in the certificate then we can + * use GNUTLS_KX_RSA or GNUTLS_KX_DHE_RSA. + */ +static const gnutls_pk_map pk_mappings[] = { + {GNUTLS_KX_RSA, GNUTLS_PK_RSA}, +/* { GNUTLS_KX_DHE_RSA, GNUTLS_PK_RSA }, */ + {0} +}; + +#define GNUTLS_PK_MAP_LOOP(b) \ + const gnutls_pk_map *p; \ + for(p = pk_mappings; p->kx_algorithm != 0; p++) { b ; } + +#define GNUTLS_PK_MAP_ALG_LOOP(a) \ + GNUTLS_PK_MAP_LOOP( if(p->kx_algorithm == kx_algorithm) { a; break; }) + + +/* returns the PKAlgorithm which is compatible with + * the given KXAlgorithm. + */ +PKAlgorithm _gnutls_map_pk_get_pk(KXAlgorithm kx_algorithm) +{ + PKAlgorithm ret = -1; + + GNUTLS_PK_MAP_ALG_LOOP(ret = p->pk_algorithm); + return ret; +} + + /* FIXME: this function is a mess */ @@ -31,8 +73,9 @@ int gnutls_read_certs(X509PKI_SERVER_CREDENTIALS * res, char *CERTFILE, { FILE *fd1, *fd2; char x[100 * 1024]; - int siz; + int siz, ret; opaque *b64; + gnutls_datum tmp; fd1 = fopen(CERTFILE, "r"); if (fd1 == NULL) @@ -52,15 +95,17 @@ int gnutls_read_certs(X509PKI_SERVER_CREDENTIALS * res, char *CERTFILE, return GNUTLS_E_PARSING_ERROR; } - res->cert_list = (gnutls_datum**) gnutls_malloc(1*sizeof(gnutls_datum*)); + res->cert_list = + (gnutls_cert **) gnutls_malloc(1 * sizeof(gnutls_cert *)); if (res->cert_list == NULL) return GNUTLS_E_MEMORY_ERROR; - res->cert_list[0] = (gnutls_datum*) gnutls_malloc(1*sizeof(gnutls_datum)); + res->cert_list[0] = + (gnutls_cert *) gnutls_malloc(1 * sizeof(gnutls_cert)); if (res->cert_list[0] == NULL) return GNUTLS_E_MEMORY_ERROR; - res->cert_list_length = (int*) gnutls_malloc(1*sizeof(int*)); + res->cert_list_length = (int *) gnutls_malloc(1 * sizeof(int *)); if (res->cert_list_length == NULL) return GNUTLS_E_MEMORY_ERROR; @@ -68,15 +113,17 @@ int gnutls_read_certs(X509PKI_SERVER_CREDENTIALS * res, char *CERTFILE, res->cert_list_length[0] = 1; - res->cert_list[0][0].data = b64; - res->cert_list[0][0].size = siz; - fclose(fd1); + tmp.data = b64; + tmp.size = siz; + if ((ret = + _gnutls_cert2gnutlsCert(&res->cert_list[0][0], tmp)) < 0) { + gnutls_assert(); + return ret; + } - - -/* second file */ +/* second file - PKCS-1 private key */ siz = fread(x, 1, sizeof(x), fd2); siz = _gnutls_fbase64_decode(x, siz, &b64); @@ -86,7 +133,7 @@ int gnutls_read_certs(X509PKI_SERVER_CREDENTIALS * res, char *CERTFILE, return GNUTLS_E_PARSING_ERROR; } - res->pkey = gnutls_malloc(1*sizeof(gnutls_datum)); + res->pkey = gnutls_malloc(1 * sizeof(gnutls_datum)); if (res->pkey == NULL) return GNUTLS_E_MEMORY_ERROR; @@ -97,3 +144,301 @@ int gnutls_read_certs(X509PKI_SERVER_CREDENTIALS * res, char *CERTFILE, return 0; } + + +static int _read_rsa_params(opaque * der, int dersize, MPI ** params) +{ + opaque str[5 * 1024]; + int len, result; + + if (create_structure + ("rsa_public_key", "PKIX1Explicit88.RSAPublicKey") != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_ERROR; + } + + result = get_der("rsa_public_key", der, dersize); + + if (result != ASN_OK) { + gnutls_assert(); + delete_structure("rsa_public_key"); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + len = sizeof(str); + result = read_value("rsa_public_key.modulus", str, &len); + if (result != ASN_OK) { + gnutls_assert(); + delete_structure("rsa_public_key"); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + /* allocate size for the parameters (2) */ + *params = gnutls_malloc(2 * sizeof(MPI)); + + if (gcry_mpi_scan(&(*params)[0], GCRYMPI_FMT_USG, str, &len) != 0) { + gnutls_assert(); + gnutls_free((*params)); + delete_structure("rsa_public_key"); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + len = sizeof(str); + result = read_value("rsa_public_key.publicExponent", str, &len); + if (result != ASN_OK) { + gnutls_assert(); + _gnutls_mpi_release(&(*params)[0]); + gnutls_free((*params)); + delete_structure("rsa_public_key"); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + + if (gcry_mpi_scan(&(*params)[1], GCRYMPI_FMT_USG, str, &len) != 0) { + gnutls_assert(); + _gnutls_mpi_release(&(*params)[0]); + gnutls_free((*params)); + delete_structure("rsa_public_key"); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + delete_structure("rsa_public_key"); + + return 0; + +} + + + +#define _READ( str, OID, NAME, res) \ + if(!strcmp(str, OID)){ \ + strcpy( str, "PKIX1Explicit88.X520"); \ + strcat( str, NAME); \ + if (create_structure( NAME, str) != ASN_OK) \ + return GNUTLS_E_ASN1_ERROR; \ + if (read_value(name3,str,&len) != ASN_OK) { \ + delete_structure( NAME); \ + return GNUTLS_E_ASN1_PARSING_ERROR; \ + } \ + if (get_der( NAME, str, len) != ASN_OK) { \ + delete_structure( NAME); \ + return GNUTLS_E_ASN1_PARSING_ERROR; \ + } \ + strcpy( name3,NAME); \ + read_value( name3, str, &len); /* CHOICE */ \ + strcat( name3, "."); \ + strcat( name3, str); \ + if (read_value(name3,str,&len) != ASN_OK) { \ + delete_structure( NAME); \ + return GNUTLS_E_ASN1_PARSING_ERROR; \ + } \ + str[len]=0; \ + res = strdup(str); \ + delete_structure(NAME); \ + } + +/* This function will attempt to read a Name + * ASN.1 structure. (Taken from Fabio's samples!) + * --nmav + */ +static int _get_Name_type(char *root, gnutls_cert * gCert) +{ + int k, k2, result, len; + char name[128], str[1024], name2[128], counter[5], name3[128]; + + k = 1; + do { + strcpy(name, root); + strcat(name, ".rdnSequence.?"); + ltostr(k, counter); + strcat(name, counter); + result = read_value(name, str, &len); + if (result == ASN_ELEMENT_NOT_FOUND) + break; + k2 = 1; + do { + strcpy(name2, name); + strcat(name2, ".?"); + ltostr(k2, counter); + strcat(name2, counter); + result = read_value(name2, str, &len); + if (result == ASN_ELEMENT_NOT_FOUND) + break; + strcpy(name3, name2); + strcat(name3, ".type"); + result = read_value(name3, str, &len); + if (result != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + strcpy(name3, name2); + strcat(name3, ".value"); + if (result == ASN_OK) { + _READ(str, "2 5 4 6", "Country", + gCert->country); + _READ(str, "2 5 4 10", "Organization", + gCert->organization); + _READ(str, "2 5 4 11", + "OrganizationalUnitName", + gCert->organizational_unit_name); + _READ(str, "2 5 4 3", "CommonName", + gCert->common_name); + _READ(str, "2 5 4 7", "LocalityName", + gCert->locality_name); + _READ(str, "2 5 4 8", + "StateOrProvinceName", + gCert->state_or_province_name); + } + k2++; + } while (1); + k++; + } while (1); + return 0; +} + + +int _gnutls_cert2gnutlsCert(gnutls_cert * gCert, gnutls_datum derCert) +{ + int result; + opaque str[5 * 1024]; + int len = sizeof(str); + + if (create_structure("certificate3", "PKIX1Explicit88.Certificate") + != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_ERROR; + } + + result = get_der("certificate3", derCert.data, derCert.size); + if (result != ASN_OK) { + /* couldn't decode DER */ + gnutls_assert(); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + + len = sizeof(str); + result = + read_value + ("certificate3.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm", + str, &len); + + if (result != ASN_OK) { + gnutls_assert(); + delete_structure("certificate3"); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + if (strcmp(str, "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 = sizeof(str); + result = + read_value + ("certificate3.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", + str, &len); + delete_structure("certificate3"); + + if (result != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + if ((result = + _read_rsa_params(str, len / 8, &gCert->params)) < 0) { + gnutls_assert(); + return result; + } + + } else { + /* other types like DH, DSA + * currently not supported + */ + gnutls_assert(); + delete_structure("certificate3"); + + return GNUTLS_E_UNIMPLEMENTED_FEATURE; + } + + /* Try to read the name + * We need a special function for that () + */ + gCert->country = NULL; + gCert->common_name = NULL; + gCert->organization = NULL; + gCert->organizational_unit_name = NULL; + gCert->locality_name = NULL; + gCert->state_or_province_name = NULL; + if ((result = + _get_Name_type("certificate3.tbsCertificate.subject", + gCert)) < 0) { + gnutls_assert(); + delete_structure("certificate3"); + return result; + } + + delete_structure("certificate3"); + + if (gnutls_set_datum(&gCert->raw, derCert.data, derCert.size) < 0) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + return 0; + +} + +/* returns the KX algorithms that are supported by a + * certificate. (Eg a certificate with RSA params, supports + * GNUTLS_KX_RSA algorithm). + */ +int _gnutls_cert_supported_kx(gnutls_cert * cert, KXAlgorithm ** alg, + int *alg_size) +{ + KXAlgorithm kx; + int i; + PKAlgorithm pk; + KXAlgorithm kxlist[255]; + + i = 0; + for (kx = 0; kx < 255; kx++) { + pk = _gnutls_map_pk_get_pk(kx); + if (pk == cert->subject_pk_algorithm) { + kxlist[i] = kx; + i++; + } + } + + *alg = gnutls_malloc(sizeof(KXAlgorithm) * i); + if (*alg == NULL) + return GNUTLS_E_MEMORY_ERROR; + + *alg_size = i; + + memcpy(*alg, kxlist, i*sizeof(KXAlgorithm)); + + return 0; +} + +/* finds a certificate in the cert list that contains + * common_name field similar to name + */ +gnutls_cert *_gnutls_find_cert(gnutls_cert ** cert_list, + int cert_list_length, char *name) +{ + gnutls_cert *cert = NULL; + int i; + + for (i = 0; i < cert_list_length; i++) { + if (cert_list[i][0].common_name != NULL) { + if (strcmp(cert_list[i][0].common_name, name) == 0) { + cert = &cert_list[i][0]; + break; + } + } + } + return cert; +} |