Version 1.1.2
- Added CRL verification functionality to certtool.
+- Corrected the CRL distribution point extension handling.
Version 1.1.1 (26/12/2003)
- Added PKCS #7 support to certtool utility.
-\subsection*{X.509 certificates}
+\subsection{X.509 certificates}
An X.509 certificate usually contains information about the certificate
-holder, the signer, a unique serial number, expiration dates etc. Some
-functions of \gnutls{}' API for certificate parsing are:
+holder, the signer, a unique serial number, expiration dates and several other
+fields\cite{RFC3280}. Some functions of \gnutls{}' API for certificate parsing are:
\begin{itemize}
\item \printfunc{gnutls_x509_crt_init}{gnutls\_x509\_crt\_init}
\item \printfunc{gnutls_x509_crt_import}{gnutls\_x509\_crt\_import}
\input{ex-x509-info}
-\subsection*{Verifying X.509 certificate paths}
+\subsection{Verifying X.509 certificate paths}
Verifying certificate\index{Verifying certificate paths} paths is important
in X.509 authentication. For this purpose the function
\printfunc{gnutls_x509_crt_verify}{gnutls\_x509\_crt\_verify} is provided. The
for an example.
-\subsection*{PKCS \#10 certificate requests\index{Certificate requests}\index
+\subsection{PKCS \#10 certificate requests\index{Certificate requests}\index
{PKCS \#10}}
A certificate request is a structure, which
is contains information about an applicant of a certificate service.
\input{ex-crq}
-\subsection*{PKCS \#12 structures\index{PKCS \#12}}
+\subsection{PKCS \#12 structures\index{PKCS \#12}}
A PKCS \#12 structure usually contains a user's private keys and
certificates. It is commonly used in browsers to export and import
the user's identities.
url = "http://kaizi.viagenie.qc.ca/ietf/rfc/rfc2945.txt"
}
+@Misc{RFC3280,
+ author = "Russell Housley and Tim Polk and Warwick Ford and David Solo",
+ title = "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile",
+ month = "April",
+ year = {2002},
+ note = "Available from http://kaizi.viagenie.qc.ca/ietf/rfc/rfc3280.txt",
+ url = "http://kaizi.viagenie.qc.ca/ietf/rfc/rfc3280.txt"
+}
+
@Misc{SSL3,
- author = "Alan O. Freier and Philip Karlton and Paul C. Kocher",
+ author = "Alan Freier and Philip Karlton and Paul Kocher",
title = "The SSL Protocol Version 3.0",
month = "November",
year = {1996},
}
@Misc{TLSSRP,
- author = "David Taylor",
+ author = "David Taylor and Trevor Perrin and Tom Wu and Nikos Mavroyanopoulos",
title = "Using SRP for TLS Authentication",
month = "June",
year = {2003},
/*
* Copyright (C) 2002,2003 Nikos Mavroyanopoulos
+ * Copyright (C) 2004 Free Software Foundation
*
* GNUTLS-EXTRA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
* Copyright (C) 2003 Nikos Mavroyanopoulos
+ * Copyright (C) 2004 Free Software Foundation
*
* This file is part of GNUTLS.
*
int gnutls_x509_crt_get_pk_algorithm( gnutls_x509_crt cert, unsigned int* bits);
int gnutls_x509_crt_get_subject_alt_name(gnutls_x509_crt cert,
- int seq, void *ret, size_t *ret_size, unsigned int* critical);
+ unsigned int seq, void *ret, size_t *ret_size, unsigned int* critical);
int gnutls_x509_crt_get_ca_status(gnutls_x509_crt cert, unsigned int* critical);
/* The key_usage flags are defined in gnutls.h. They are
/*
* Copyright (C) 2000,2001,2002,2003 Nikos Mavroyanopoulos
+ * Copyright (C) 2004 Free Software Foundation
*
* This file is part of GNUTLS.
*
DistributionPoint ::= SEQUENCE {
distributionPoint [0] DistributionPointName OPTIONAL,
reasons [1] ReasonFlags OPTIONAL,
- cRLIssuer [2] GeneralNames OPTIONAL }
-
-DistributionPointName ::= CHOICE {
- fullName [0] GeneralNames,
- nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
-
--- Those are used to raw write a fullname.
-
-WritableCRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF WritableDistributionPoint
+ cRLIssuer [2] GeneralNames OPTIONAL
+}
-WritableDistributionPoint ::= SEQUENCE {
- distributionPoint [0] WriteableDistributionPointName OPTIONAL,
- reasons [1] ReasonFlags OPTIONAL,
- cRLIssuer [2] GeneralNames OPTIONAL }
+-- original definition:
+-- DistributionPointName ::= CHOICE {
+-- fullName [0] GeneralNames,
+-- nameRelativeToCRLIssuer [1] RelativeDistinguishedName
+--}
+-- This does not work since it does not tag elements.
-WriteableDistributionPointName ::= CHOICE {
- fullName [0] ANY,
- nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
+DistributionPointName ::= SEQUENCE {
+ fullName [0] GeneralNames
+-- nameRelativeToCRLIssuer [1] RelativeDistinguishedName
+}
ReasonFlags ::= BIT STRING {
unused (0),
{0,4104,"1"},
{"cRLIssuer",536895490,"GeneralNames"},
{0,4104,"2"},
- {"DistributionPointName",1610612754,0},
- {"fullName",1610620930,"GeneralNames"},
+ {"DistributionPointName",1610612741,0},
+ {"fullName",536879106,"GeneralNames"},
{0,4104,"0"},
- {"nameRelativeToCRLIssuer",536879106,"RelativeDistinguishedName"},
- {0,4104,"1"},
- {"WritableCRLDistributionPoints",1612709899,0},
- {"MAX",1074266122,"1"},
- {0,2,"WritableDistributionPoint"},
- {"WritableDistributionPoint",1610612741,0},
- {"distributionPoint",1610637314,"WriteableDistributionPointName"},
- {0,4104,"0"},
- {"reasons",1610637314,"ReasonFlags"},
- {0,4104,"1"},
- {"cRLIssuer",536895490,"GeneralNames"},
- {0,4104,"2"},
- {"WriteableDistributionPointName",1610612754,0},
- {"fullName",1610620941,0},
- {0,4104,"0"},
- {"nameRelativeToCRLIssuer",536879106,"RelativeDistinguishedName"},
- {0,4104,"1"},
{"ReasonFlags",1610874886,0},
{"unused",1073741825,"0"},
{"keyCompromise",1073741825,"1"},
return _gnutls_asn2err(result);
}
- if (strcmp( str_critical, "TRUE")==0)
+ if (str_critical[0] == 'T')
critical = 1;
else critical = 0;
if (result != ASN1_SUCCESS) {
gnutls_assert();
asn1_delete_structure(&ext);
- return 0;
+ return _gnutls_asn2err(result);
}
len = sizeof(str);
if (result != ASN1_SUCCESS) {
gnutls_assert();
asn1_delete_structure(&ext);
- return 0;
+ return _gnutls_asn2err(result);
}
len = sizeof(str) - 1;
+ /* the default value of cA is false.
+ */
result = asn1_read_value(ext, "cA", str, &len);
if (result != ASN1_SUCCESS) {
- gnutls_assert();
asn1_delete_structure(&ext);
return 0;
}
return 0;
}
-/* generate the subject alternative name in a DER encoded extension
- */
-int _gnutls_x509_ext_gen_subject_alt_name(gnutls_x509_subject_alt_name type,
- const char* data_string, gnutls_datum* der_ext)
+static int write_new_general_name( ASN1_TYPE ext, const char* ext_name,
+ gnutls_x509_subject_alt_name type, const char* data_string)
{
- ASN1_TYPE ext = ASN1_TYPE_EMPTY;
- const char *str;
- char name[128];
- int result;
-
- result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.SubjectAltName", &ext);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- return _gnutls_asn2err(result);
- }
+const char* str;
+int result;
+char name[128];
- result = asn1_write_value( ext, "", "NEW", 1);
+ result = asn1_write_value( ext, ext_name, "NEW", 1);
if (result != ASN1_SUCCESS) {
gnutls_assert();
return _gnutls_asn2err(result);
return GNUTLS_E_INTERNAL_ERROR;
}
- result = asn1_write_value( ext, "?LAST", str, 1);
+ if (ext_name[0] == 0) { /* no dot */
+ _gnutls_str_cpy( name, sizeof(name), "?LAST");
+ } else {
+ _gnutls_str_cpy( name, sizeof(name), ext_name);
+ _gnutls_str_cat( name, sizeof(name), ".?LAST");
+ }
+
+ result = asn1_write_value( ext, name, str, 1);
if (result != ASN1_SUCCESS) {
gnutls_assert();
return _gnutls_asn2err(result);
}
- _gnutls_str_cpy( name, sizeof(name), "?LAST.");
+ _gnutls_str_cat( name, sizeof(name), ".");
_gnutls_str_cat( name, sizeof(name), str);
result = asn1_write_value(ext, name, data_string, strlen(data_string));
return _gnutls_asn2err(result);
}
+ return 0;
+}
+
+/* Convert the given name to GeneralNames in a DER encoded extension.
+ * This is the same as subject alternative name.
+ */
+int _gnutls_x509_ext_gen_subject_alt_name(gnutls_x509_subject_alt_name type,
+ const char* data_string, gnutls_datum* der_ext)
+{
+ ASN1_TYPE ext = ASN1_TYPE_EMPTY;
+ int result;
+
+ result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.GeneralNames", &ext);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ result = write_new_general_name(ext, "", type, data_string);
+ if (result < 0) {
+ gnutls_assert();
+ asn1_delete_structure(&ext);
+ return result;
+ }
+
result = _gnutls_x509_der_encode( ext, "", der_ext, 0);
asn1_delete_structure(&ext);
return 0;
}
-
+/* Creates and encodes the CRL Distribution points. data_string should be a name
+ * and type holds the type of the name.
+ * reason_flags should be an or'ed sequence of GNUTLS_CRL_REASON_*.
+ *
+ */
int _gnutls_x509_ext_gen_crl_dist_points(gnutls_x509_subject_alt_name type,
const void* data_string, unsigned int reason_flags, gnutls_datum* der_ext)
{
ASN1_TYPE ext = ASN1_TYPE_EMPTY;
- gnutls_datum name = {NULL, 0};
+ gnutls_datum gnames = {NULL, 0};
int result;
uint8 reasons[2];
reasons[0] = reason_flags & 0xff;
reasons[1] = reason_flags >> 8;
- result = _gnutls_x509_ext_gen_subject_alt_name( type, data_string, &name);
- if (result < 0) {
- gnutls_assert();
- return result;
- }
-
- result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.WritableCRLDistributionPoints", &ext);
+ result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.CRLDistributionPoints", &ext);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
goto cleanup;
}
+#if 0
+ /* When used as type CHOICE.
+ */
result = asn1_write_value( ext, "?LAST.distributionPoint", "fullName", 1);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
goto cleanup;
}
+#endif
- result = asn1_write_value( ext, "?LAST.distributionPoint.fullName", name.data, name.size);
- if (result != ASN1_SUCCESS) {
+ result = write_new_general_name(ext, "?LAST.distributionPoint.fullName", type, data_string);
+ if (result < 0) {
gnutls_assert();
- result = _gnutls_asn2err(result);
goto cleanup;
}
result = 0;
cleanup:
- _gnutls_free_datum( &name);
+ _gnutls_free_datum( &gnames);
asn1_delete_structure(&ext);
return result;
}
+/* returns the type and the name.
+ */
+static int parse_general_name( ASN1_TYPE src, const char* src_name,
+ int seq, void* name, size_t *name_size)
+{
+int len;
+char num[MAX_INT_DIGITS];
+char nptr[128];
+int result;
+opaque choice_type[128];
+gnutls_x509_subject_alt_name type;
+
+ seq++; /* 0->1, 1->2 etc */
+ _gnutls_int2str( seq, num);
+
+ _gnutls_str_cpy( nptr, sizeof(nptr), src_name);
+ if (src_name[0] != 0) _gnutls_str_cat( nptr, sizeof(nptr), ".");
+
+ _gnutls_str_cat( nptr, sizeof(nptr), "?");
+ _gnutls_str_cat( nptr, sizeof(nptr), num);
+
+ len = sizeof(choice_type);
+ result =
+ asn1_read_value(src, nptr, choice_type, &len);
+
+ if (result == ASN1_VALUE_NOT_FOUND || result == ASN1_ELEMENT_NOT_FOUND) {
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+
+ type = _gnutls_x509_san_find_type( choice_type);
+ if (type == (gnutls_x509_subject_alt_name)-1) {
+ gnutls_assert();
+ return GNUTLS_E_X509_UNKNOWN_SAN;
+ }
+
+ _gnutls_str_cat( nptr, sizeof(nptr), ".");
+ _gnutls_str_cat( nptr, sizeof(nptr), choice_type);
+
+ len = *name_size;
+ result =
+ asn1_read_value(src, nptr, name, &len);
+ *name_size = len;
+
+ if (result==ASN1_MEM_ERROR)
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ return type;
+}
+
/**
* gnutls_x509_crt_get_subject_alt_name - This function returns the certificate's alternative name, if any
* @cert: should contain a gnutls_x509_crt structure
*
**/
int gnutls_x509_crt_get_subject_alt_name(gnutls_x509_crt cert,
- int seq, void *ret, size_t *ret_size, unsigned int *critical)
+ unsigned int seq, void *ret, size_t *ret_size, unsigned int *critical)
{
int result;
gnutls_datum dnsname;
ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
- char nptr[128];
- char ext_data[256];
- int len;
- char num[MAX_INT_DIGITS];
gnutls_x509_subject_alt_name type;
if (cert==NULL) {
return _gnutls_asn2err(result);
}
- seq++; /* 0->1, 1->2 etc */
- _gnutls_int2str( seq, num);
- _gnutls_str_cpy( nptr, sizeof(nptr), "?");
- _gnutls_str_cat( nptr, sizeof(nptr), num);
-
- len = sizeof(ext_data);
- result =
- asn1_read_value(c2, nptr, ext_data, &len);
-
- if (result == ASN1_VALUE_NOT_FOUND || result == ASN1_ELEMENT_NOT_FOUND) {
- asn1_delete_structure(&c2);
- return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
- }
-
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- asn1_delete_structure(&c2);
- return _gnutls_asn2err(result);
- }
-
-
- type = _gnutls_x509_san_find_type( ext_data);
- if (type == (gnutls_x509_subject_alt_name)-1) {
- asn1_delete_structure(&c2);
- gnutls_assert();
- return GNUTLS_E_X509_UNKNOWN_SAN;
- }
+ result = parse_general_name( c2, "", seq, ret, ret_size);
- _gnutls_str_cat( nptr, sizeof(nptr), ".");
- _gnutls_str_cat( nptr, sizeof(nptr), ext_data);
-
- len = *ret_size;
- result =
- asn1_read_value(c2, nptr, ret, &len);
asn1_delete_structure(&c2);
- *ret_size = len;
- if (result==ASN1_MEM_ERROR)
- return GNUTLS_E_SHORT_MEMORY_BUFFER;
-
- if (result != ASN1_SUCCESS) {
+ if (result < 0) {
gnutls_assert();
- return _gnutls_asn2err(result);
+ return result;
}
+ type = result;
+
return type;
}
gnutls_datum dist_points = {NULL, 0};
ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
char name[128];
- char ext_data[256];
int len;
char num[MAX_INT_DIGITS];
gnutls_x509_subject_alt_name type;
result =
_gnutls_x509_crt_get_extension(cert, "2.5.29.31", 0, &dist_points, critical);
if (result < 0) {
- gnutls_assert();
return result;
}
return _gnutls_asn2err(result);
}
- seq++; /* 0->1, 1->2 etc */
- _gnutls_int2str( seq, num);
- _gnutls_str_cpy( name, sizeof(name), "dn.?");
- _gnutls_str_cat( name, sizeof(name), num);
- _gnutls_str_cat( name, sizeof(name), ".distributionPoint.fullName");
-
- len = sizeof(ext_data);
- result =
- asn1_read_value(c2, name, ext_data, &len);
-
- if (result == ASN1_VALUE_NOT_FOUND) {
- asn1_delete_structure(&c2);
- return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
- }
+ /* Return the different names from the first CRLDistr. point.
+ * The whole thing is a mess.
+ */
+ _gnutls_str_cpy( name, sizeof(name), "?1.distributionPoint.fullName");
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
+ result = parse_general_name( c2, name, seq, ret, ret_size);
+ if (result < 0) {
asn1_delete_structure(&c2);
- return _gnutls_asn2err(result);
+ return result;
}
+
+ type = result;
/* Read the CRL reasons.
*/
if (reason_flags) {
- _gnutls_str_cpy( name, sizeof(name), "dn.?");
+ _gnutls_str_cpy( name, sizeof(name), "?");
_gnutls_str_cat( name, sizeof(name), num);
_gnutls_str_cat( name, sizeof(name), ".reasons");
*reason_flags = reasons[0] | (reasons[1] << 8);
}
-
-
- type = _gnutls_x509_san_find_type( ext_data);
- if (type == (gnutls_x509_subject_alt_name)-1) {
- asn1_delete_structure(&c2);
- gnutls_assert();
- return GNUTLS_E_X509_UNKNOWN_SAN;
- }
-
- _gnutls_str_cat( name, sizeof(name), ".");
- _gnutls_str_cat( name, sizeof(name), ext_data);
-
- len = *ret_size;
- result =
- asn1_read_value(c2, name, ret, &len);
- asn1_delete_structure(&c2);
-
- *ret_size = len;
-
- if (result==ASN1_MEM_ERROR)
- return GNUTLS_E_SHORT_MEMORY_BUFFER;
-
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- return _gnutls_asn2err(result);
- }
return type;
}
int gnutls_x509_crt_get_issuer_dn_by_oid(gnutls_x509_crt cert, const char* oid,
int indx, unsigned int raw_flag, void *buf, size_t *sizeof_buf);
int gnutls_x509_crt_get_subject_alt_name(gnutls_x509_crt cert,
- int seq, void *ret, size_t *ret_size, unsigned int* critical);
+ unsigned int seq, void *ret, size_t *ret_size, unsigned int* critical);
int gnutls_x509_crt_get_dn_by_oid(gnutls_x509_crt cert, const char* oid,
int indx, unsigned int raw_flag, void *buf, size_t *sizeof_buf);
int gnutls_x509_crt_get_ca_status(gnutls_x509_crt cert, unsigned int* critical);
#include <time.h>
#include "certtool-gaa.h"
#include <gnutls/pkcs12.h>
+#include <fileio.h>
#include <unistd.h>
static void print_crl_info( gnutls_x509_crl crl, FILE* out, int all);
gnutls_x509_privkey key;
size_t size;
int result;
+ const char *uri;
fprintf(stderr, "Generating a self signed certificate...\n");
crt = generate_certificate( &key);
+ uri = read_str( "Enter the URI of the CRL distribution point: ");
+ if (uri) {
+ result = gnutls_x509_crt_set_crl_dist_points( crt, GNUTLS_SAN_URI,
+ uri, 0 /* all reasons */);
+ if (result < 0) {
+ fprintf(stderr, "crl_dist_points: %s\n", gnutls_strerror(result));
+ exit(1);
+ }
+ }
+
print_certificate_info( crt, stderr, 0);
fprintf(stderr, "\n\nSigning certificate...\n");
ret = gnutls_x509_crt_get_crl_dist_points(crt, i, buffer, &size, NULL, &critical);
if (i==0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
- fprintf(outfile, "\tCRL Distribution points:");
- if (critical) fprintf(outfile, " (critical)");
- fprintf(outfile, "\n");
+ fprintf(out, "\tCRL Distribution points:");
+ if (critical) fprintf(out, " (critical)");
+ fprintf(out, "\n");
}
if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
- fprintf(outfile, "\t\tError decoding: %s\n", gnutls_strerror(ret));
+ fprintf(out, "\t\tError decoding: %s\n", gnutls_strerror(ret));
} else switch (ret) {
case GNUTLS_SAN_DNSNAME:
- fprintf(outfile, "\t\tDNSname: %s\n", buffer);
+ fprintf(out, "\t\tDNSname: %s\n", buffer);
break;
case GNUTLS_SAN_RFC822NAME:
- fprintf(outfile, "\t\tRFC822name: %s\n", buffer);
+ fprintf(out, "\t\tRFC822name: %s\n", buffer);
break;
case GNUTLS_SAN_URI:
- fprintf(outfile, "\t\tURI: %s\n", buffer);
+ fprintf(out, "\t\tURI: %s\n", buffer);
break;
case GNUTLS_SAN_IPADDRESS:
- fprintf(outfile, "\t\tIPAddress: %s\n", buffer);
+ fprintf(out, "\t\tIPAddress: %s\n", buffer);
break;
}
}