summaryrefslogtreecommitdiff
path: root/lib/gnutls_cert.c
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2002-02-01 11:14:47 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2002-02-01 11:14:47 +0000
commit4eb7eee2eebdf38466a955b73e122933422491bf (patch)
tree9719b14062087936fd518b56b7afbe64d382f969 /lib/gnutls_cert.c
parent0a048d3c44bb23f6856587779c5ae0435d54f388 (diff)
downloadgnutls-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.c1212
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, &params[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, &params[1])) < 0) {
- gnutls_assert();
- _gnutls_mpi_release(&params[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, &params[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, &params[1])) < 0) {
- gnutls_assert();
- asn1_delete_structure(spk);
- _gnutls_mpi_release(&params[0]);
- return GNUTLS_E_ASN1_PARSING_ERROR;
- }
-
- /* Read g */
-
- if ( (result=_gnutls_x509_read_int( spk, "dsa_parms.g", str, sizeof(str)-1, &params[2])) < 0) {
- gnutls_assert();
- asn1_delete_structure(spk);
- _gnutls_mpi_release(&params[0]);
- _gnutls_mpi_release(&params[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, &params[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;
+ }
+}