diff --git a/lib/hx509/ChangeLog b/lib/hx509/ChangeLog index f924cc249..e879eba0c 100644 --- a/lib/hx509/ChangeLog +++ b/lib/hx509/ChangeLog @@ -1,3 +1,7 @@ +2007-12-11 Love Hörnquist Åstrand + + * *.[ch]: More documentation + 2007-12-09 Love Hörnquist Åstrand * handle refcount on NULL. diff --git a/lib/hx509/cert.c b/lib/hx509/cert.c index 38b237d1a..5ca885e3a 100644 --- a/lib/hx509/cert.c +++ b/lib/hx509/cert.c @@ -36,6 +36,19 @@ RCSID("$Id$"); #include "crypto-headers.h" #include +/** + * @page page_cert The basic certificate + * + * The basic hx509 cerificate object in hx509 is hx509_cert. The + * hx509_cert object is representing one X509/PKIX certificate and + * associated attributes; like private key, friendly name, etc. + * + * A hx509_cert object is usully found via the keyset interfaces (@ref + * page_keyset), but its also possible to create a certificate + * directly from a parsed object with hx509_cert_init() and + * hx509_cert_init_data(). + */ + struct hx509_verify_ctx_data { hx509_certs trust_anchors; int flags; diff --git a/lib/hx509/cms.c b/lib/hx509/cms.c index fb2a0407d..2285e6ac6 100644 --- a/lib/hx509/cms.c +++ b/lib/hx509/cms.c @@ -34,9 +34,42 @@ #include "hx_locl.h" RCSID("$Id$"); +/** + * @page page_cms CMS/PKCS7 message functions. + * + * CMS is defined in RFC 3369 and is an continuation of the RSA Labs + * standard PKCS7. The basic messages in CMS is + * + * - SignedData + * Data signed with private key (RSA, DSA, ECDSA) or secret + * (symmetric) key + * - EnvelopedData + * Data encrypted with private key (RSA) + * - EncryptedData + * Data encrypted with secret (symmetric) key. + * - ContentInfo + * Wrapper structure including type and data. + * + */ + #define ALLOC(X, N) (X) = calloc((N), sizeof(*(X))) #define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0) +/** + * Wrap data and oid in a ContentInfo and encode it. + * + * @param oid type of the content. + * @param buf data to be wrapped. If a NULL pointer is passed in, the + * optional content field in the ContentInfo is not going be filled + * in. + * @param res the encoded buffer, the result should be freed with + * der_free_octet_string(). + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_cms + */ + int hx509_cms_wrap_ContentInfo(const heim_oid *oid, const heim_octet_string *buf, @@ -52,18 +85,20 @@ hx509_cms_wrap_ContentInfo(const heim_oid *oid, ret = der_copy_oid(oid, &ci.contentType); if (ret) return ret; - ALLOC(ci.content, 1); - if (ci.content == NULL) { - free_ContentInfo(&ci); - return ENOMEM; + if (buf) { + ALLOC(ci.content, 1); + if (ci.content == NULL) { + free_ContentInfo(&ci); + return ENOMEM; + } + ci.content->data = malloc(buf->length); + if (ci.content->data == NULL) { + free_ContentInfo(&ci); + return ENOMEM; + } + memcpy(ci.content->data, buf->data, buf->length); + ci.content->length = buf->length; } - ci.content->data = malloc(buf->length); - if (ci.content->data == NULL) { - free_ContentInfo(&ci); - return ENOMEM; - } - memcpy(ci.content->data, buf->data, buf->length); - ci.content->length = buf->length; ASN1_MALLOC_ENCODE(ContentInfo, res->data, res->length, &ci, &size, ret); free_ContentInfo(&ci); @@ -75,6 +110,20 @@ hx509_cms_wrap_ContentInfo(const heim_oid *oid, return 0; } +/** + * Decode an ContentInfo and unwrap data and oid it. + * + * @param in the encoded buffer. + * @param oid type of the content. + * @param buf data to be wrapped. + * @param have_data since the data is optional, this flags show dthe + * diffrence between no data and the zero length data. + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_cms + */ + int hx509_cms_unwrap_ContentInfo(const heim_octet_string *in, heim_oid *oid, @@ -108,7 +157,7 @@ hx509_cms_unwrap_ContentInfo(const heim_octet_string *in, memset(out, 0, sizeof(*out)); if (have_data) - *have_data = (ci.content != NULL) ? 1 : 0; + *have_data = (ci.vcontent != NULL) ? 1 : 0; free_ContentInfo(&ci); @@ -267,6 +316,23 @@ find_CMSIdentifier(hx509_context context, return 0; } +/** + * Decode and unencrypt EnvelopedData. + * + * Separate data from the EnvelopedData. + * + * @param context + * @param certs + * @param flags + * @param data + * @param length + * @param encryptedContent + * @param contentType + * @param content + * + * @ingroup hx509_cms + */ + int hx509_cms_unenvelope(hx509_context context, hx509_certs certs, diff --git a/lib/hx509/doxygen.c b/lib/hx509/doxygen.c index 0e0a17272..3da79d143 100644 --- a/lib/hx509/doxygen.c +++ b/lib/hx509/doxygen.c @@ -31,23 +31,38 @@ * SUCH DAMAGE. */ -/*! \mainpage Heimdal X.509 library +/** @mainpage Heimdal PKIX/X.509 library * - * \section intro Introduction + * @section intro Introduction * - * Heimdal libhx509 library is a implementation of the X.509 and + * Heimdal libhx509 library is a implementation of the PKIX/X.509 and * related protocols. * - * X.509 is ... + * PKIX/X.509 is ... * - * The project web page:\n + * + * Sections in this manual are: + * - @ref page_name + * - @ref page_cert + * - @ref page_keyset + * - @ref page_revoke + * - @ref page_cms + * + * The project web page: * http://www.h5l.org/ * */ /** @defgroup hx509 hx509 library */ -/** @defgroup hx509_cert hx509 certificate functions */ -/** @defgroup hx509_verify hx509 verification functions */ -/** @defgroup hx509_name hx509 name functions */ + +/** @defgroup hx509_cert hx509 certificate functions + * See the @ref page_cert for description and examples. */ +/** @defgroup hx509_cms hx509 name functions + * See the @ref page_cms for description and examples. */ /** @defgroup hx509_crypto hx509 crypto functions */ /** @defgroup hx509_misc hx509 misc functions */ +/** @defgroup hx509_name hx509 name functions + * See the @ref page_name for description and examples. */ +/** @defgroup hx509_revoke hx509 revokation checking functions + * See the @ref page_revoke for description and examples. */ +/** @defgroup hx509_verify hx509 verification functions */ diff --git a/lib/hx509/keyset.c b/lib/hx509/keyset.c index 1494f0efe..77b1e7abe 100644 --- a/lib/hx509/keyset.c +++ b/lib/hx509/keyset.c @@ -34,6 +34,11 @@ #include "hx_locl.h" RCSID("$Id$"); +/** + * @page page_keyset Keyset operations + * + */ + struct hx509_certs_data { int ref; struct hx509_keyset_ops *ops; diff --git a/lib/hx509/name.c b/lib/hx509/name.c index 61077ad0c..0af65e091 100644 --- a/lib/hx509/name.c +++ b/lib/hx509/name.c @@ -34,10 +34,28 @@ #include "hx_locl.h" RCSID("$Id$"); -/* - * name parsing from rfc2253 - * fix so parsing rfc1779 works too - * rfc3280 +/** + * @page page_name PKIX/X.509 Names + * + * There are several names in PKIX/X.509, GeneralName and Name. + * + * A Name consists of an ordered list of Relative Distinguished Names + * (RDN). Each RDN consists of an unordered list of typed strings. The + * types are defined by OID and have long and short description. For + * example id-at-commonName (2.5.4.3) have the long name CommonName + * and short name CN. The string itself can be of serveral encoding, + * UTF8, UTF16, Teltex string, etc. The type limit what encoding + * should be used. + * + * GeneralName is a broader nametype that can contains al kind of + * stuff like Name, IP addresses, partial Name, etc. + * + * Name is mapped into a hx509_name object. + * + * Parse and string name into a hx509_name object with hx509_parse_name(), + * make it back into string representation with hx509_name_to_string(). + * + * Name string are defined rfc2253, rfc1779 and X.501. */ static const struct { @@ -385,19 +403,6 @@ _hx509_name_from_Name(const Name *n, hx509_name *name) return ret; } -static int -hx509_der_parse_name(const void *data, size_t length, hx509_name *name) -{ - int ret; - Name n; - - *name = NULL; - ret = decode_Name(data, length, &n, NULL); - if (ret) - return ret; - return _hx509_name_from_Name(&n, name); -} - int _hx509_name_modify(hx509_context context, Name *name, @@ -577,6 +582,17 @@ hx509_name_copy(hx509_context context, const hx509_name from, hx509_name *to) return 0; } +/** + * Convert a hx509_name into a Name. + * + * @param from the name to copy from + * @param to the name to copy to + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_name + */ + int hx509_name_to_Name(const hx509_name from, Name *to) { @@ -589,6 +605,19 @@ hx509_name_normalize(hx509_context context, hx509_name name) return 0; } +/** + * Expands variables in the name using env. Variables are on the form + * ${name}. Useful when dealing with certificate templates. + * + * @param context A hx509 cotext. + * @param name the name to expand. + * @param env environment variable to expand. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_name + */ + int hx509_name_expand(hx509_context context, hx509_name name, @@ -607,6 +636,7 @@ hx509_name_expand(hx509_context context, for (i = 0 ; i < n->u.rdnSequence.len; i++) { for (j = 0; j < n->u.rdnSequence.val[i].len; j++) { + /** Only UTF8String rdnSequence names are allowed */ /* THIS SHOULD REALLY BE: COMP = n->u.rdnSequence.val[i].val[j]; @@ -704,7 +734,7 @@ hx509_name_free(hx509_name *name) * Convert a DER encoded name info a string. * * @param data data to a DER/BER encoded name -? * @param length length of data + * @param length length of data * @param str the resulting string, is NULL on failure. * * @return An hx509 error code, see hx509_get_error_string(). @@ -712,22 +742,34 @@ hx509_name_free(hx509_name *name) * @ingroup hx509_name */ - int hx509_unparse_der_name(const void *data, size_t length, char **str) { - hx509_name name; + Name name; int ret; - ret = hx509_der_parse_name(data, length, &name); + *str = NULL; + + ret = decode_Name(data, length, &name, NULL); if (ret) return ret; - - ret = hx509_name_to_string(name, str); - hx509_name_free(&name); + ret = _hx509_Name_to_string(&name, str); + free_Name(&name); return ret; } +/** + * Convert a hx509_name object to DER encoded name. + * + * @param name name to concert + * @param data data to a DER encoded name + * @param length length of data + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_name + */ + int hx509_name_to_der_name(const hx509_name name, void **data, size_t *length) { @@ -743,7 +785,6 @@ hx509_name_to_der_name(const hx509_name name, void **data, size_t *length) return 0; } - int _hx509_unparse_Name(const Name *aname, char **str) { @@ -759,6 +800,16 @@ _hx509_unparse_Name(const Name *aname, char **str) return ret; } +/** + * Unparse the hx509 name in name into a string. + * + * @param name the name to check if its empty/null. + * + * @return non zero if the name is empty/null. + * + * @ingroup hx509_name + */ + int hx509_name_is_null_p(const hx509_name name) { diff --git a/lib/hx509/revoke.c b/lib/hx509/revoke.c index 496ab8dff..25d274fac 100644 --- a/lib/hx509/revoke.c +++ b/lib/hx509/revoke.c @@ -31,6 +31,24 @@ * SUCH DAMAGE. */ +/** + * @page page_revoke Revocation methods + * + * There are two revocation method for PKIX/X.509: CRL and OCSP. + * Revocation is needed if the private key is lost and + * stolen. Depending on how picky you are, you might want to make + * revocation for destroyed private keys too (smartcard broken), but + * that should not be a problem. + * + * CRL is a list of certifiates that have expired. + * + * OCSP is an online checking method where the requestor sends a list + * of certificates to the OCSP server to return a signed reply if they + * are valid or not. Some services sends a OCSP reply as part of the + * hand-shake to make the revoktion decision simpler/faster for the + * client. + */ + #include "hx_locl.h" RCSID("$Id$"); @@ -63,6 +81,17 @@ struct hx509_revoke_ctx_data { } ocsps; }; +/** + * Allocate a revokation context. Free with hx509_revoke_free(). + * + * @param context A hx509 context. + * @param ctx returns a newly allocated revokation context. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_revoke + */ + int hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx) { @@ -101,6 +130,14 @@ free_ocsp(struct revoke_ocsp *ocsp) hx509_cert_free(ocsp->signer); } +/** + * Free a hx509 revokation context. + * + * @param ctx context to be freed + * + * @ingroup hx509_revoke + */ + void hx509_revoke_free(hx509_revoke_ctx *ctx) { @@ -345,6 +382,18 @@ load_ocsp(hx509_context context, struct revoke_ocsp *ocsp) return 0; } +/** + * Add a OCSP file to the revokation context. + * + * @param context hx509 context + * @param ctx hx509 revokation context + * @param path path to file that is going to be added to the context. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_revoke + */ + int hx509_revoke_add_ocsp(hx509_context context, hx509_revoke_ctx ctx, @@ -537,6 +586,18 @@ load_crl(const char *path, time_t *t, CRLCertificateList *crl) return 0; } +/** + * Add a CRL file to the revokation context. + * + * @param context hx509 context + * @param ctx hx509 revokation context + * @param path path to file that is going to be added to the context. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_revoke + */ + int hx509_revoke_add_crl(hx509_context context, hx509_revoke_ctx ctx, @@ -589,6 +650,23 @@ hx509_revoke_add_crl(hx509_context context, return ret; } +/** + * Check that a certificate is not expired according to a revokation + * context. Also need the parent certificte to the check OCSP + * parent identifier. + * + * @param context hx509 context + * @param ctx hx509 revokation context + * @param certs + * @param now + * @param cert + * @param parent_cert + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_revoke + */ + int hx509_revoke_verify(hx509_context context, @@ -861,6 +939,22 @@ out: return ret; } +/** + * Create an OCSP request for a set of certificates. + * + * @param context a hx509 context + * @param reqcerts list of certificates to request ocsp data for + * @param pool certificate pool to use when signing + * @param signer certificate to use to sign the request + * @param digest the signing algorithm in the request, if NULL use the + * default signature algorithm, + * @param request the encoded request, free with free_heim_octet_string(). + * @param nonce nonce in the request, free with free_heim_octet_string(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_revoke + */ int hx509_ocsp_request(hx509_context context, @@ -889,41 +983,49 @@ hx509_ocsp_request(hx509_context context, ret = hx509_certs_iter(context, reqcerts, add_to_req, &ctx); hx509_cert_free(ctx.parent); - if (ret) { - free_OCSPRequest(&req); - return ret; - } + if (ret) + goto out; if (nonce) { - req.tbsRequest.requestExtensions = calloc(1, sizeof(*req.tbsRequest.requestExtensions)); if (req.tbsRequest.requestExtensions == NULL) { - free_OCSPRequest(&req); - return ENOMEM; + ret = ENOMEM; + goto out; } es = req.tbsRequest.requestExtensions; - es->len = 1; es->val = calloc(es->len, sizeof(es->val[0])); + if (es->val == NULL) { + ret = ENOMEM; + goto out; + } + es->len = 1; ret = der_copy_oid(oid_id_pkix_ocsp_nonce(), &es->val[0].extnID); - if (ret) - abort(); - + if (ret) { + free_OCSPRequest(&req); + return ret; + } + es->val[0].extnValue.data = malloc(10); if (es->val[0].extnValue.data == NULL) { - free_OCSPRequest(&req); - return ENOMEM; + ret = ENOMEM; + goto out; } es->val[0].extnValue.length = 10; ret = RAND_bytes(es->val[0].extnValue.data, es->val[0].extnValue.length); if (ret != 1) { - free_OCSPRequest(&req); - return HX509_CRYPTO_INTERNAL_ERROR; + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + ret = der_copy_octet_string(nonce, &es->val[0].extnValue); + if (ret) { + ret = ENOMEM; + goto out; } } @@ -931,12 +1033,15 @@ hx509_ocsp_request(hx509_context context, &req, &size, ret); free_OCSPRequest(&req); if (ret) - return ret; + goto out; if (size != request->length) _hx509_abort("internal ASN.1 encoder error"); - return 0; + +out: + free_OCSPRequest(&req); + return ret; } static char * @@ -948,6 +1053,18 @@ printable_time(time_t t) return s; } +/** + * Print the OCSP reply stored in a file. + * + * @param context a hx509 context + * @param path path to a file with a OCSP reply + * @param out the out FILE descriptor to print the reply on + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_revoke + */ + int hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out) { @@ -1035,10 +1152,23 @@ hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out) return ret; } -/* - * Verify that the `cert' is part of the OCSP reply and it's not +/** + * Verify that the certificate is part of the OCSP reply and it's not * expired. Doesn't verify signature the OCSP reply or it's done by a * authorized sender, that is assumed to be already done. + * + * @param context a hx509 context + * @param now the time right now, if 0, use the current time. + * @param cert the certificate to verify + * @param flags flags control the behavior + * @param data pointer to the encode ocsp reply + * @param length the length of the encode ocsp reply + * @param expiration return the time the OCSP will expire and need to + * be rechecked. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_verify */ int @@ -1138,6 +1268,17 @@ struct hx509_crl { time_t expire; }; +/** + * Create a CRL context. Use hx509_crl_free() to free the CRL context. + * + * @param context a hx509 context. + * @param crl return pointer to a newly allocated CRL context. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_verify + */ + int hx509_crl_alloc(hx509_context context, hx509_crl *crl) { @@ -1159,6 +1300,18 @@ hx509_crl_alloc(hx509_context context, hx509_crl *crl) return ret; } +/** + * Add revoked certificate to an CRL context. + * + * @param context a hx509 context. + * @param crl the CRL to add the revoked certificate to. + * @param certs keyset of certificate to revoke. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_verify + */ + int hx509_crl_add_revoked_certs(hx509_context context, hx509_crl crl, @@ -1167,6 +1320,19 @@ hx509_crl_add_revoked_certs(hx509_context context, return hx509_certs_merge(context, crl->revoked, certs); } +/** + * Set the lifetime of a CRL context. + * + * @param context a hx509 context. + * @param crl a CRL context + * @param delta delta time the certificate is valid, library adds the + * current time to this. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_verify + */ + int hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta) { @@ -1174,6 +1340,14 @@ hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta) return 0; } +/** + * Free a CRL context. + * + * @param context a hx509 context. + * @param crl a CRL context to free. + * + * @ingroup hx509_verify + */ void hx509_crl_free(hx509_context context, hx509_crl *crl) @@ -1220,6 +1394,19 @@ add_revoked(hx509_context context, void *ctx, hx509_cert cert) return 0; } +/** + * Sign a CRL and return an encode certificate. + * + * @param context a hx509 context. + * @param signer certificate to sign the CRL with + * @param crl the CRL to sign + * @param os return the signed and encoded CRL, free with + * free_heim_octet_string() + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_verify + */ int hx509_crl_sign(hx509_context context,