summaryrefslogtreecommitdiff
path: root/source4/heimdal/lib/hx509
diff options
context:
space:
mode:
Diffstat (limited to 'source4/heimdal/lib/hx509')
-rw-r--r--source4/heimdal/lib/hx509/ca.c334
-rw-r--r--source4/heimdal/lib/hx509/cert.c878
-rw-r--r--source4/heimdal/lib/hx509/cms.c173
-rw-r--r--source4/heimdal/lib/hx509/crypto.c194
-rw-r--r--source4/heimdal/lib/hx509/env.c52
-rw-r--r--source4/heimdal/lib/hx509/error.c81
-rw-r--r--source4/heimdal/lib/hx509/hx509-private.h52
-rw-r--r--source4/heimdal/lib/hx509/hx509-protos.h47
-rw-r--r--source4/heimdal/lib/hx509/hx509.h7
-rw-r--r--source4/heimdal/lib/hx509/hx509_err.et4
-rw-r--r--source4/heimdal/lib/hx509/hx_locl.h6
-rw-r--r--source4/heimdal/lib/hx509/keyset.c237
-rw-r--r--source4/heimdal/lib/hx509/ks_file.c38
-rw-r--r--source4/heimdal/lib/hx509/ks_keychain.c10
-rw-r--r--source4/heimdal/lib/hx509/ks_p11.c4
-rw-r--r--source4/heimdal/lib/hx509/lock.c8
-rw-r--r--source4/heimdal/lib/hx509/name.c367
-rw-r--r--source4/heimdal/lib/hx509/peer.c54
-rw-r--r--source4/heimdal/lib/hx509/print.c200
-rw-r--r--source4/heimdal/lib/hx509/revoke.c398
20 files changed, 2735 insertions, 409 deletions
diff --git a/source4/heimdal/lib/hx509/ca.c b/source4/heimdal/lib/hx509/ca.c
index bf8fe1be1a4..40260700b3f 100644
--- a/source4/heimdal/lib/hx509/ca.c
+++ b/source4/heimdal/lib/hx509/ca.c
@@ -33,7 +33,13 @@
#include "hx_locl.h"
#include <pkinit_asn1.h>
-RCSID("$Id: ca.c 21379 2007-06-28 07:38:17Z lha $");
+RCSID("$Id: ca.c 22456 2008-01-15 20:22:53Z lha $");
+
+/**
+ * @page page_ca Hx509 CA functions
+ *
+ * See the library functions here: @ref hx509_ca
+ */
struct hx509_ca_tbs {
hx509_name subject;
@@ -55,6 +61,19 @@ struct hx509_ca_tbs {
CRLDistributionPoints crldp;
};
+/**
+ * Allocate an to-be-signed certificate object that will be converted
+ * into an certificate.
+ *
+ * @param context A hx509 context.
+ * @param tbs returned to-be-signed certicate object, free with
+ * hx509_ca_tbs_free().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_init(hx509_context context, hx509_ca_tbs *tbs)
{
@@ -74,6 +93,14 @@ hx509_ca_tbs_init(hx509_context context, hx509_ca_tbs *tbs)
return 0;
}
+/**
+ * Free an To Be Signed object.
+ *
+ * @param tbs object to free.
+ *
+ * @ingroup hx509_ca
+ */
+
void
hx509_ca_tbs_free(hx509_ca_tbs *tbs)
{
@@ -93,6 +120,19 @@ hx509_ca_tbs_free(hx509_ca_tbs *tbs)
*tbs = NULL;
}
+/**
+ * Set the absolute time when the certificate is valid from. If not
+ * set the current time will be used.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param t time the certificated will start to be valid
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_set_notBefore(hx509_context context,
hx509_ca_tbs tbs,
@@ -102,6 +142,18 @@ hx509_ca_tbs_set_notBefore(hx509_context context,
return 0;
}
+/**
+ * Set the absolute time when the certificate is valid to.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param t time when the certificate will expire
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_set_notAfter(hx509_context context,
hx509_ca_tbs tbs,
@@ -111,6 +163,18 @@ hx509_ca_tbs_set_notAfter(hx509_context context,
return 0;
}
+/**
+ * Set the relative time when the certificiate is going to expire.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param delta seconds to the certificate is going to expire.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_set_notAfter_lifetime(hx509_context context,
hx509_ca_tbs tbs,
@@ -130,12 +194,35 @@ static const struct units templatebits[] = {
{ NULL, 0 }
};
+/**
+ * Make of template units, use to build flags argument to
+ * hx509_ca_tbs_set_template() with parse_units().
+ *
+ * @return an units structure.
+ *
+ * @ingroup hx509_ca
+ */
+
const struct units *
hx509_ca_tbs_template_units(void)
{
return templatebits;
}
+/**
+ * Initialize the to-be-signed certificate object from a template certifiate.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param flags bit field selecting what to copy from the template
+ * certifiate.
+ * @param cert template certificate.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_set_template(hx509_context context,
hx509_ca_tbs tbs,
@@ -170,12 +257,10 @@ hx509_ca_tbs_set_template(hx509_context context,
tbs->notAfter = hx509_cert_get_notAfter(cert);
if (flags & HX509_CA_TEMPLATE_SPKI) {
free_SubjectPublicKeyInfo(&tbs->spki);
- ret = hx509_cert_get_SPKI(cert, &tbs->spki);
+ ret = hx509_cert_get_SPKI(context, cert, &tbs->spki);
tbs->flags.key = !ret;
- if (ret) {
- hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
+ if (ret)
return ret;
- }
}
if (flags & HX509_CA_TEMPLATE_KU) {
KeyUsage ku;
@@ -202,6 +287,20 @@ hx509_ca_tbs_set_template(hx509_context context,
return 0;
}
+/**
+ * Make the to-be-signed certificate object a CA certificate. If the
+ * pathLenConstraint is negative path length constraint is used.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param pathLenConstraint path length constraint, negative, no
+ * constraint.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_set_ca(hx509_context context,
hx509_ca_tbs tbs,
@@ -212,6 +311,20 @@ hx509_ca_tbs_set_ca(hx509_context context,
return 0;
}
+/**
+ * Make the to-be-signed certificate object a proxy certificate. If the
+ * pathLenConstraint is negative path length constraint is used.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param pathLenConstraint path length constraint, negative, no
+ * constraint.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_set_proxy(hx509_context context,
hx509_ca_tbs tbs,
@@ -223,6 +336,17 @@ hx509_ca_tbs_set_proxy(hx509_context context,
}
+/**
+ * Make the to-be-signed certificate object a windows domain controller certificate.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_set_domaincontroller(hx509_context context,
hx509_ca_tbs tbs)
@@ -231,6 +355,20 @@ hx509_ca_tbs_set_domaincontroller(hx509_context context,
return 0;
}
+/**
+ * Set the subject public key info (SPKI) in the to-be-signed certificate
+ * object. SPKI is the public key and key related parameters in the
+ * certificate.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param spki subject public key info to use for the to-be-signed certificate object.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_set_spki(hx509_context context,
hx509_ca_tbs tbs,
@@ -243,6 +381,19 @@ hx509_ca_tbs_set_spki(hx509_context context,
return ret;
}
+/**
+ * Set the serial number to use for to-be-signed certificate object.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param serialNumber serial number to use for the to-be-signed
+ * certificate object.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_set_serialnumber(hx509_context context,
hx509_ca_tbs tbs,
@@ -255,6 +406,19 @@ hx509_ca_tbs_set_serialnumber(hx509_context context,
return ret;
}
+/**
+ * An an extended key usage to the to-be-signed certificate object.
+ * Duplicates will detected and not added.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param oid extended key usage to add.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_add_eku(hx509_context context,
hx509_ca_tbs tbs,
@@ -285,6 +449,20 @@ hx509_ca_tbs_add_eku(hx509_context context,
return 0;
}
+/**
+ * Add CRL distribution point URI to the to-be-signed certificate
+ * object.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param uri uri to the CRL.
+ * @param issuername name of the issuer.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_add_crl_dp_uri(hx509_context context,
hx509_ca_tbs tbs,
@@ -325,6 +503,9 @@ hx509_ca_tbs_add_crl_dp_uri(hx509_context context,
if (issuername) {
#if 1
+ /**
+ * issuername not supported
+ */
hx509_set_error_string(context, 0, EINVAL,
"CRLDistributionPoints.name.issuername not yet supported");
return EINVAL;
@@ -372,6 +553,20 @@ out:
return ret;
}
+/**
+ * Add Subject Alternative Name otherName to the to-be-signed
+ * certificate object.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param oid the oid of the OtherName.
+ * @param os data in the other name.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_add_san_otherName(hx509_context context,
hx509_ca_tbs tbs,
@@ -388,6 +583,18 @@ hx509_ca_tbs_add_san_otherName(hx509_context context,
return add_GeneralNames(&tbs->san, &gn);
}
+/**
+ * Add Kerberos Subject Alternative Name to the to-be-signed
+ * certificate object. The principal string is a UTF8 string.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param principal Kerberos principal to add to the certificate.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
int
hx509_ca_tbs_add_san_pkinit(hx509_context context,
@@ -511,6 +718,19 @@ out:
return ret;
}
+/**
+ * Add Microsoft UPN Subject Alternative Name to the to-be-signed
+ * certificate object. The principal string is a UTF8 string.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param principal Microsoft UPN string.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_add_san_ms_upn(hx509_context context,
hx509_ca_tbs tbs,
@@ -519,6 +739,19 @@ hx509_ca_tbs_add_san_ms_upn(hx509_context context,
return add_utf8_san(context, tbs, oid_id_pkinit_ms_san(), principal);
}
+/**
+ * Add a Jabber/XMPP jid Subject Alternative Name to the to-be-signed
+ * certificate object. The jid is an UTF8 string.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param jid string of an a jabber id in UTF8.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_add_san_jid(hx509_context context,
hx509_ca_tbs tbs,
@@ -528,6 +761,22 @@ hx509_ca_tbs_add_san_jid(hx509_context context,
}
+/**
+ * Add a Subject Alternative Name hostname to to-be-signed certificate
+ * object. A domain match starts with ., an exact match does not.
+ *
+ * Example of a an domain match: .domain.se matches the hostname
+ * host.domain.se.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param dnsname a hostame.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_add_san_hostname(hx509_context context,
hx509_ca_tbs tbs,
@@ -542,6 +791,19 @@ hx509_ca_tbs_add_san_hostname(hx509_context context,
return add_GeneralNames(&tbs->san, &gn);
}
+/**
+ * Add a Subject Alternative Name rfc822 (email address) to
+ * to-be-signed certificate object.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param rfc822Name a string to a email address.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_add_san_rfc822name(hx509_context context,
hx509_ca_tbs tbs,
@@ -556,6 +818,17 @@ hx509_ca_tbs_add_san_rfc822name(hx509_context context,
return add_GeneralNames(&tbs->san, &gn);
}
+/**
+ * Set the subject name of a to-be-signed certificate object.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param subject the name to set a subject.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
int
hx509_ca_tbs_set_subject(hx509_context context,
@@ -567,6 +840,20 @@ hx509_ca_tbs_set_subject(hx509_context context,
return hx509_name_copy(context, subject, &tbs->subject);
}
+/**
+ * Expand the the subject name in the to-be-signed certificate object
+ * using hx509_name_expand().
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param env enviroment variable to expand variables in the subject
+ * name, see hx509_env_init().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_tbs_subject_expand(hx509_context context,
hx509_ca_tbs tbs,
@@ -1148,6 +1435,30 @@ out:
}
+/**
+ * Sign a to-be-signed certificate object with a issuer certificate.
+ *
+ * The caller needs to at least have called the following functions on the
+ * to-be-signed certificate object:
+ * - hx509_ca_tbs_init()
+ * - hx509_ca_tbs_set_subject()
+ * - hx509_ca_tbs_set_spki()
+ *
+ * When done the to-be-signed certificate object should be freed with
+ * hx509_ca_tbs_free().
+ *
+ * When creating self-signed certificate use hx509_ca_sign_self() instead.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param signer the CA certificate object to sign with (need private key).
+ * @param certificate return cerificate, free with hx509_cert_free().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_sign(hx509_context context,
hx509_ca_tbs tbs,
@@ -1179,6 +1490,19 @@ out:
return ret;
}
+/**
+ * Work just like hx509_ca_sign() but signs it-self.
+ *
+ * @param context A hx509 context.
+ * @param tbs object to be signed.
+ * @param signer private key to sign with.
+ * @param certificate return cerificate, free with hx509_cert_free().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_ca
+ */
+
int
hx509_ca_sign_self(hx509_context context,
hx509_ca_tbs tbs,
diff --git a/source4/heimdal/lib/hx509/cert.c b/source4/heimdal/lib/hx509/cert.c
index b7f19d152a9..09c85bc0841 100644
--- a/source4/heimdal/lib/hx509/cert.c
+++ b/source4/heimdal/lib/hx509/cert.c
@@ -32,10 +32,25 @@
*/
#include "hx_locl.h"
-RCSID("$Id: cert.c 21380 2007-06-28 07:38:38Z lha $");
+RCSID("$Id: cert.c 22583 2008-02-11 20:46:21Z lha $");
#include "crypto-headers.h"
#include <rtbl.h>
+/**
+ * @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().
+ *
+ * See the library functions here: @ref hx509_cert
+ */
+
struct hx509_verify_ctx_data {
hx509_certs trust_anchors;
int flags;
@@ -78,8 +93,16 @@ typedef struct hx509_name_constraints {
#define GeneralSubtrees_SET(g,var) \
(g)->len = (var)->len, (g)->val = (var)->val;
-/*
+/**
+ * Creates a hx509 context that most functions in the library
+ * uses. The context is only allowed to be used by one thread at each
+ * moment. Free the context with hx509_context_free().
*
+ * @param context Returns a pointer to new hx509 context.
+ *
+ * @return Returns an hx509 error code.
+ *
+ * @ingroup hx509
*/
int
@@ -113,6 +136,19 @@ hx509_context_init(hx509_context *context)
return 0;
}
+/**
+ * Selects if the hx509_revoke_verify() function is going to require
+ * the existans of a revokation method (OSCP, CRL) or not. Note that
+ * hx509_verify_path(), hx509_cms_verify_signed(), and other function
+ * call hx509_revoke_verify().
+ *
+ * @param context hx509 context to change the flag for.
+ * @param flag zero, revokation method required, non zero missing
+ * revokation method ok
+ *
+ * @ingroup hx509_verify
+ */
+
void
hx509_context_set_missing_revoke(hx509_context context, int flag)
{
@@ -122,6 +158,14 @@ hx509_context_set_missing_revoke(hx509_context context, int flag)
context->flags &= ~HX509_CTX_VERIFY_MISSING_OK;
}
+/**
+ * Free the context allocated by hx509_context_init().
+ *
+ * @param context context to be freed.
+ *
+ * @ingroup hx509
+ */
+
void
hx509_context_free(hx509_context *context)
{
@@ -139,7 +183,6 @@ hx509_context_free(hx509_context *context)
*context = NULL;
}
-
/*
*
*/
@@ -154,39 +197,25 @@ _hx509_get_cert(hx509_cert cert)
*
*/
-#if 0
-void
-_hx509_print_cert_subject(hx509_cert cert)
-{
- char *subject_name;
- hx509_name name;
- int ret;
-
- ret = hx509_cert_get_subject(cert, &name);
- if (ret)
- abort();
-
- ret = hx509_name_to_string(name, &subject_name);
- hx509_name_free(&name);
- if (ret)
- abort();
-
- printf("name: %s\n", subject_name);
-
- free(subject_name);
-}
-#endif
-
-/*
- *
- */
-
int
_hx509_cert_get_version(const Certificate *t)
{
return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1;
}
+/**
+ * Allocate and init an hx509 certificate object from the decoded
+ * certificate `cī.
+ *
+ * @param context A hx509 context.
+ * @param c
+ * @param cert
+ *
+ * @return Returns an hx509 error code.
+ *
+ * @ingroup hx509_cert
+ */
+
int
hx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert)
{
@@ -218,9 +247,29 @@ hx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert)
return ret;
}
+/**
+ * Just like hx509_cert_init(), but instead of a decode certificate
+ * takes an pointer and length to a memory region that contains a
+ * DER/BER encoded certificate.
+ *
+ * If the memory region doesn't contain just the certificate and
+ * nothing more the function will fail with
+ * HX509_EXTRA_DATA_AFTER_STRUCTURE.
+ *
+ * @param context A hx509 context.
+ * @param ptr pointer to memory region containing encoded certificate.
+ * @param len length of memory region.
+ * @param cert a return pointer to a hx509 certificate object, will
+ * contain NULL on error.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
int
hx509_cert_init_data(hx509_context context,
- const void *ptr,
+ const void *ptr,
size_t len,
hx509_cert *cert)
{
@@ -265,6 +314,15 @@ _hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
return 0;
}
+/**
+ * Free reference to the hx509 certificate object, if the refcounter
+ * reaches 0, the object if freed. Its allowed to pass in NULL.
+ *
+ * @param cert the cert to free.
+ *
+ * @ingroup hx509_cert
+ */
+
void
hx509_cert_free(hx509_cert cert)
{
@@ -274,7 +332,7 @@ hx509_cert_free(hx509_cert cert)
return;
if (cert->ref <= 0)
- _hx509_abort("refcount <= 0");
+ _hx509_abort("cert refcount <= 0 on free");
if (--cert->ref > 0)
return;
@@ -300,9 +358,21 @@ hx509_cert_free(hx509_cert cert)
free(cert);
}
+/**
+ * Add a reference to a hx509 certificate object.
+ *
+ * @param cert a pointer to an hx509 certificate object.
+ *
+ * @return the same object as is passed in.
+ *
+ * @ingroup hx509_cert
+ */
+
hx509_cert
hx509_cert_ref(hx509_cert cert)
{
+ if (cert == NULL)
+ return NULL;
if (cert->ref <= 0)
_hx509_abort("cert refcount <= 0");
cert->ref++;
@@ -311,6 +381,18 @@ hx509_cert_ref(hx509_cert cert)
return cert;
}
+/**
+ * Allocate an verification context that is used fo control the
+ * verification process.
+ *
+ * @param context A hx509 context.
+ * @param ctx returns a pointer to a hx509_verify_ctx object.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_verify
+ */
+
int
hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
{
@@ -327,26 +409,75 @@ hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
return 0;
}
+/**
+ * Free an hx509 verification context.
+ *
+ * @param ctx the context to be freed.
+ *
+ * @ingroup hx509_verify
+ */
+
void
hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
{
- if (ctx)
+ if (ctx) {
+ hx509_certs_free(&ctx->trust_anchors);
+ hx509_revoke_free(&ctx->revoke_ctx);
memset(ctx, 0, sizeof(*ctx));
+ }
free(ctx);
}
+/**
+ * Set the trust anchors in the verification context, makes an
+ * reference to the keyset, so the consumer can free the keyset
+ * independent of the destruction of the verification context (ctx).
+ *
+ * @param ctx a verification context
+ * @param set a keyset containing the trust anchors.
+ *
+ * @ingroup hx509_verify
+ */
+
void
hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
{
- ctx->trust_anchors = set;
+ ctx->trust_anchors = _hx509_certs_ref(set);
}
+/**
+ * Attach an revocation context to the verfication context, , makes an
+ * reference to the revoke context, so the consumer can free the
+ * revoke context independent of the destruction of the verification
+ * context. If there is no revoke context, the verification process is
+ * NOT going to check any verification status.
+ *
+ * @param ctx a verification context.
+ * @param revoke_ctx a revoke context.
+ *
+ * @ingroup hx509_verify
+ */
+
void
hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
{
- ctx->revoke_ctx = revoke_ctx;
+ if (ctx->revoke_ctx)
+ hx509_revoke_free(&ctx->revoke_ctx);
+ ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
}
+/**
+ * Set the clock time the the verification process is going to
+ * use. Used to check certificate in the past and future time. If not
+ * set the current time will be used.
+ *
+ * @param ctx a verification context.
+ * @param t the time the verifiation is using.
+ *
+ *
+ * @ingroup hx509_verify
+ */
+
void
hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
{
@@ -354,12 +485,32 @@ hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
ctx->time_now = t;
}
+/**
+ * Set the maximum depth of the certificate chain that the path
+ * builder is going to try.
+ *
+ * @param ctx a verification context
+ * @param max_depth maxium depth of the certificate chain, include
+ * trust anchor.
+ *
+ * @ingroup hx509_verify
+ */
+
void
hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
{
ctx->max_depth = max_depth;
}
+/**
+ * Allow or deny the use of proxy certificates
+ *
+ * @param ctx a verification context
+ * @param boolean if non zero, allow proxy certificates.
+ *
+ * @ingroup hx509_verify
+ */
+
void
hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
{
@@ -369,6 +520,17 @@ hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
}
+/**
+ * Select strict RFC3280 verification of certificiates. This means
+ * checking key usage on CA certificates, this will make version 1
+ * certificiates unuseable.
+ *
+ * @param ctx a verification context
+ * @param boolean if non zero, use strict verification.
+ *
+ * @ingroup hx509_verify
+ */
+
void
hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
{
@@ -378,6 +540,20 @@ hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
}
+/**
+ * Allow using the operating system builtin trust anchors if no other
+ * trust anchors are configured.
+ *
+ * @param ctx a verification context
+ * @param boolean if non zero, useing the operating systems builtin
+ * trust anchors.
+ *
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
void
hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
{
@@ -512,6 +688,15 @@ add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
return 0;
}
+/**
+ * Free a list of octet strings returned by another hx509 library
+ * function.
+ *
+ * @param list list to be freed.
+ *
+ * @ingroup hx509_misc
+ */
+
void
hx509_free_octet_string_list(hx509_octet_string_list *list)
{
@@ -523,8 +708,26 @@ hx509_free_octet_string_list(hx509_octet_string_list *list)
list->len = 0;
}
+/**
+ * Return a list of subjectAltNames specified by oid in the
+ * certificate. On error the
+ *
+ * The returned list of octet string should be freed with
+ * hx509_free_octet_string_list().
+ *
+ * @param context A hx509 context.
+ * @param cert a hx509 certificate object.
+ * @param oid an oid to for SubjectAltName.
+ * @param list list of matching SubjectAltName.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
int
-hx509_cert_find_subjectAltName_otherName(hx509_cert cert,
+hx509_cert_find_subjectAltName_otherName(hx509_context context,
+ hx509_cert cert,
const heim_oid *oid,
hx509_octet_string_list *list)
{
@@ -541,9 +744,11 @@ hx509_cert_find_subjectAltName_otherName(hx509_cert cert,
if (ret == HX509_EXTENSION_NOT_FOUND) {
ret = 0;
break;
- } else if (ret != 0)
- break;
-
+ } else if (ret != 0) {
+ hx509_set_error_string(context, 0, ret, "Error searching for SAN");
+ hx509_free_octet_string_list(list);
+ return ret;
+ }
for (j = 0; j < sa.len; j++) {
if (sa.val[j].element == choice_GeneralName_otherName &&
@@ -551,6 +756,10 @@ hx509_cert_find_subjectAltName_otherName(hx509_cert cert,
{
ret = add_to_list(list, &sa.val[j].u.otherName.value);
if (ret) {
+ hx509_set_error_string(context, 0, ret,
+ "Error adding an exra SAN to "
+ "return list");
+ hx509_free_octet_string_list(list);
free_GeneralNames(&sa);
return ret;
}
@@ -558,7 +767,7 @@ hx509_cert_find_subjectAltName_otherName(hx509_cert cert,
}
free_GeneralNames(&sa);
}
- return ret;
+ return 0;
}
@@ -605,6 +814,12 @@ check_key_usage(hx509_context context, const Certificate *cert,
return 0;
}
+/*
+ * Return 0 on matching key usage 'flags' for 'cert', otherwise return
+ * an error code. If 'req_present' the existance is required of the
+ * KeyUsage extension.
+ */
+
int
_hx509_check_key_usage(hx509_context context, hx509_cert cert,
unsigned flags, int req_present)
@@ -678,10 +893,13 @@ _hx509_cert_is_parent_cmp(const Certificate *subject,
int diff;
AuthorityKeyIdentifier ai;
SubjectKeyIdentifier si;
- int ret_ai, ret_si;
+ int ret_ai, ret_si, ret;
- diff = _hx509_name_cmp(&issuer->tbsCertificate.subject,
- &subject->tbsCertificate.issuer);
+ ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
+ &subject->tbsCertificate.issuer,
+ &diff);
+ if (ret)
+ return ret;
if (diff)
return diff;
@@ -689,7 +907,7 @@ _hx509_cert_is_parent_cmp(const Certificate *subject,
memset(&si, 0, sizeof(si));
/*
- * Try to find AuthorityKeyIdentifier, if its not present in the
+ * Try to find AuthorityKeyIdentifier, if it's not present in the
* subject certificate nor the parent.
*/
@@ -736,8 +954,11 @@ _hx509_cert_is_parent_cmp(const Certificate *subject,
name.u.rdnSequence =
ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
- diff = _hx509_name_cmp(&issuer->tbsCertificate.subject,
- &name);
+ ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
+ &name,
+ &diff);
+ if (ret)
+ return ret;
if (diff)
return diff;
diff = 0;
@@ -776,13 +997,22 @@ certificate_is_anchor(hx509_context context,
}
static int
-certificate_is_self_signed(const Certificate *cert)
-{
- return _hx509_cert_is_parent_cmp(cert, cert, 1) == 0;
+certificate_is_self_signed(hx509_context context,
+ const Certificate *cert,
+ int *self_signed)
+{
+ int ret, diff;
+ ret = _hx509_name_cmp(&cert->tbsCertificate.subject,
+ &cert->tbsCertificate.issuer, &diff);
+ *self_signed = (diff == 0);
+ if (ret)
+ hx509_set_error_string(context, 0, ret,
+ "Failed to check if self signed");
+ return ret;
}
/*
- * The subjectName is "null" when its empty set of relative DBs.
+ * The subjectName is "null" when it's empty set of relative DBs.
*/
static int
@@ -1032,9 +1262,9 @@ _hx509_calculate_path(hx509_context context,
return 0;
}
-static int
-AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
- const AlgorithmIdentifier *q)
+int
+_hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
+ const AlgorithmIdentifier *q)
{
int diff;
diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
@@ -1061,8 +1291,8 @@ _hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
if (diff)
return diff;
- diff = AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
- &q->signatureAlgorithm);
+ diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
+ &q->signatureAlgorithm);
if (diff)
return diff;
diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
@@ -1070,24 +1300,77 @@ _hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
return diff;
}
+/**
+ * Compare to hx509 certificate object, useful for sorting.
+ *
+ * @param p a hx509 certificate object.
+ * @param q a hx509 certificate object.
+ *
+ * @return 0 the objects are the same, returns > 0 is p is "larger"
+ * then q, < 0 if p is "smaller" then q.
+ *
+ * @ingroup hx509_cert
+ */
+
int
hx509_cert_cmp(hx509_cert p, hx509_cert q)
{
return _hx509_Certificate_cmp(p->data, q->data);
}
+/**
+ * Return the name of the issuer of the hx509 certificate.
+ *
+ * @param p a hx509 certificate object.
+ * @param name a pointer to a hx509 name, should be freed by
+ * hx509_name_free().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
int
hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
{
return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
}
+/**
+ * Return the name of the subject of the hx509 certificate.
+ *
+ * @param p a hx509 certificate object.
+ * @param name a pointer to a hx509 name, should be freed by
+ * hx509_name_free(). See also hx509_cert_get_base_subject().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
int
hx509_cert_get_subject(hx509_cert p, hx509_name *name)
{
return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
}
+/**
+ * Return the name of the base subject of the hx509 certificate. If
+ * the certiicate is a verified proxy certificate, the this function
+ * return the base certificate (root of the proxy chain). If the proxy
+ * certificate is not verified with the base certificate
+ * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
+ *
+ * @param context a hx509 context.
+ * @param c a hx509 certificate object.
+ * @param name a pointer to a hx509 name, should be freed by
+ * hx509_name_free(). See also hx509_cert_get_subject().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
int
hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
hx509_name *name)
@@ -1104,31 +1387,107 @@ hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
}
+/**
+ * Get serial number of the certificate.
+ *
+ * @param p a hx509 certificate object.
+ * @param i serial number, should be freed ith der_free_heim_integer().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
int
hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
{
return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
}
+/**
+ * Get notBefore time of the certificate.
+ *
+ * @param p a hx509 certificate object.
+ *
+ * @return return not before time
+ *
+ * @ingroup hx509_cert
+ */
+
time_t
hx509_cert_get_notBefore(hx509_cert p)
{
return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
}
+/**
+ * Get notAfter time of the certificate.
+ *
+ * @param p a hx509 certificate object.
+ *
+ * @return return not after time.
+ *
+ * @ingroup hx509_cert
+ */
+
time_t
hx509_cert_get_notAfter(hx509_cert p)
{
return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
}
+/**
+ * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
+ *
+ * @param context a hx509 context.
+ * @param p a hx509 certificate object.
+ * @param spki SubjectPublicKeyInfo, should be freed with
+ * free_SubjectPublicKeyInfo().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
+int
+hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki)
+{
+ int ret;
+
+ ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki);
+ if (ret)
+ hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
+ return ret;
+}
+
+/**
+ * Get the AlgorithmIdentifier from the hx509 certificate.
+ *
+ * @param context a hx509 context.
+ * @param p a hx509 certificate object.
+ * @param alg AlgorithmIdentifier, should be freed with
+ * free_AlgorithmIdentifier().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
int
-hx509_cert_get_SPKI(hx509_cert p, SubjectPublicKeyInfo *spki)
+hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context,
+ hx509_cert p,
+ AlgorithmIdentifier *alg)
{
- return copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo,
- spki);
+ int ret;
+
+ ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg);
+ if (ret)
+ hx509_set_error_string(context, 0, ret,
+ "Failed to copy SPKI AlgorithmIdentifier");
+ return ret;
}
+
hx509_private_key
_hx509_cert_private_key(hx509_cert p)
{
@@ -1136,6 +1495,13 @@ _hx509_cert_private_key(hx509_cert p)
}
int
+hx509_cert_have_private_key(hx509_cert p)
+{
+ return p->private_key ? 1 : 0;
+}
+
+
+int
_hx509_cert_private_key_exportable(hx509_cert p)
{
if (p->private_key == NULL)
@@ -1253,9 +1619,14 @@ match_RDN(const RelativeDistinguishedName *c,
return HX509_NAME_CONSTRAINT_ERROR;
for (i = 0; i < n->len; i++) {
+ int diff, ret;
+
if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
return HX509_NAME_CONSTRAINT_ERROR;
- if (_hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value) != 0)
+ ret = _hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value, &diff);
+ if (ret)
+ return ret;
+ if (diff != 0)
return HX509_NAME_CONSTRAINT_ERROR;
}
return 0;
@@ -1316,7 +1687,7 @@ match_general_name(const GeneralName *c, const GeneralName *n, int *match)
return HX509_NAME_CONSTRAINT_ERROR;
if (strcasecmp(s + 1 + len2 - len1, c->u.rfc822Name) != 0)
return HX509_NAME_CONSTRAINT_ERROR;
- if (len1 < len2 && s[len2 - len1] != '.')
+ if (len1 < len2 && s[len2 - len1 + 1] != '.')
return HX509_NAME_CONSTRAINT_ERROR;
}
*match = 1;
@@ -1387,7 +1758,6 @@ match_alt_name(const GeneralName *n, const Certificate *c,
}
free_GeneralNames(&sa);
} while (1);
-
return ret;
}
@@ -1457,7 +1827,10 @@ check_name_constraints(hx509_context context,
}
/* allow null subjectNames, they wont matches anything */
if (match == 0 && !subject_null_p(c)) {
- hx509_clear_error_string(context);
+ hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
+ "Error verify constraints, "
+ "certificate didn't match any "
+ "permitted subtree");
return HX509_VERIFY_CONSTRAINTS;
}
}
@@ -1469,7 +1842,10 @@ check_name_constraints(hx509_context context,
return ret;
}
if (match) {
- hx509_clear_error_string(context);
+ hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
+ "Error verify constraints, "
+ "certificate included in excluded "
+ "subtree");
return HX509_VERIFY_CONSTRAINTS;
}
}
@@ -1487,6 +1863,21 @@ free_name_constraints(hx509_name_constraints *nc)
free(nc->val);
}
+/**
+ * Build and verify the path for the certificate to the trust anchor
+ * specified in the verify context. The path is constructed from the
+ * certificate, the pool and the trust anchors.
+ *
+ * @param context A hx509 context.
+ * @param ctx A hx509 verification context.
+ * @param cert the certificate to build the path from.
+ * @param pool A keyset of certificates to build the chain from.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_verify
+ */
+
int
hx509_verify_path(hx509_context context,
hx509_verify_ctx ctx,
@@ -1495,10 +1886,7 @@ hx509_verify_path(hx509_context context,
{
hx509_name_constraints nc;
hx509_path path;
-#if 0
- const AlgorithmIdentifier *alg_id;
-#endif
- int ret, i, proxy_cert_depth;
+ int ret, i, proxy_cert_depth, selfsigned_depth, diff;
enum certtype type;
Name proxy_issuer;
hx509_certs anchors = NULL;
@@ -1538,10 +1926,6 @@ hx509_verify_path(hx509_context context,
if (ret)
goto out;
-#if 0
- alg_id = path.val[path->len - 1]->data->tbsCertificate.signature;
-#endif
-
/*
* Check CA and proxy certificate chain from the top of the
* certificate chain. Also check certificate is valid with respect
@@ -1550,6 +1934,7 @@ hx509_verify_path(hx509_context context,
*/
proxy_cert_depth = 0;
+ selfsigned_depth = 0;
if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
type = PROXY_CERT;
@@ -1570,6 +1955,7 @@ hx509_verify_path(hx509_context context,
switch (type) {
case CA_CERT:
+
/* XXX make constants for keyusage */
ret = check_key_usage(context, c, 1 << 5,
REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
@@ -1578,6 +1964,18 @@ hx509_verify_path(hx509_context context,
"Key usage missing from CA certificate");
goto out;
}
+
+ /* self signed cert doesn't add to path length */
+ if (i + 1 != path.len) {
+ int selfsigned;
+
+ ret = certificate_is_self_signed(context, c, &selfsigned);
+ if (ret)
+ goto out;
+ if (selfsigned)
+ selfsigned_depth++;
+ }
+
break;
case PROXY_CERT: {
ProxyCertInfo info;
@@ -1624,8 +2022,12 @@ hx509_verify_path(hx509_context context,
*/
if (proxy_cert_depth) {
- ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject);
+ ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject, &diff);
if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ if (diff) {
ret = HX509_PROXY_CERT_NAME_WRONG;
hx509_set_error_string(context, 0, ret,
"Base proxy name not right");
@@ -1658,8 +2060,12 @@ hx509_verify_path(hx509_context context,
free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
proxy_issuer.u.rdnSequence.len -= 1;
- ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer);
- if (ret != 0) {
+ ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer, &diff);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ if (diff != 0) {
ret = HX509_PROXY_CERT_NAME_WRONG;
hx509_set_error_string(context, 0, ret,
"Proxy issuer name not as expected");
@@ -1685,9 +2091,13 @@ hx509_verify_path(hx509_context context,
*/
if (proxy_cert_depth) {
- ret = _hx509_name_cmp(&proxy_issuer,
- &c->tbsCertificate.subject);
+ ret = _hx509_name_cmp(&proxy_issuer,
+ &c->tbsCertificate.subject, &diff);
if (ret) {
+ hx509_set_error_string(context, 0, ret, "out of memory");
+ goto out;
+ }
+ if (diff) {
ret = HX509_PROXY_CERT_NAME_WRONG;
hx509_clear_error_string(context);
goto out;
@@ -1705,7 +2115,8 @@ hx509_verify_path(hx509_context context,
break;
}
- ret = check_basic_constraints(context, c, type, i - proxy_cert_depth);
+ ret = check_basic_constraints(context, c, type,
+ i - proxy_cert_depth - selfsigned_depth);
if (ret)
goto out;
@@ -1742,22 +2153,16 @@ hx509_verify_path(hx509_context context,
for (ret = 0, i = path.len - 1; i >= 0; i--) {
Certificate *c;
+ int selfsigned;
c = _hx509_get_cert(path.val[i]);
-#if 0
- /* check that algorithm and parameters is the same */
- /* XXX this is wrong */
- ret = alg_cmp(&c->tbsCertificate.signature, alg_id);
- if (ret) {
- hx509_clear_error_string(context);
- ret = HX509_PATH_ALGORITHM_CHANGED;
+ ret = certificate_is_self_signed(context, c, &selfsigned);
+ if (ret)
goto out;
- }
-#endif
/* verify name constraints, not for selfsigned and anchor */
- if (!certificate_is_self_signed(c) || i == path.len - 1) {
+ if (!selfsigned || i + 1 != path.len) {
ret = check_name_constraints(context, &nc, c);
if (ret) {
goto out;
@@ -1813,12 +2218,6 @@ hx509_verify_path(hx509_context context,
hx509_certs_free(&certs);
}
-#if 0
- for (i = path.len - 1; i >= 0; i--) {
- _hx509_print_cert_subject(path.val[i]);
- }
-#endif
-
/*
* Verify signatures, do this backward so public key working
* parameter is passed up from the anchor up though the chain.
@@ -1830,11 +2229,17 @@ hx509_verify_path(hx509_context context,
c = _hx509_get_cert(path.val[i]);
/* is last in chain (trust anchor) */
- if (i == path.len - 1) {
+ if (i + 1 == path.len) {
+ int selfsigned;
+
signer = path.val[i]->data;
+ ret = certificate_is_self_signed(context, signer, &selfsigned);
+ if (ret)
+ goto out;
+
/* if trust anchor is not self signed, don't check sig */
- if (!certificate_is_self_signed(signer))
+ if (!selfsigned)
continue;
} else {
/* take next certificate in chain */
@@ -1863,6 +2268,20 @@ out:
return ret;
}
+/**
+ * Verify a signature made using the private key of an certificate.
+ *
+ * @param context A hx509 context.
+ * @param signer the certificate that made the signature.
+ * @param alg algorthm that was used to sign the data.
+ * @param data the data that was signed.
+ * @param sig the sigature to verify.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_crypto
+ */
+
int
hx509_verify_signature(hx509_context context,
const hx509_cert signer,
@@ -1873,7 +2292,26 @@ hx509_verify_signature(hx509_context context,
return _hx509_verify_signature(context, signer->data, alg, data, sig);
}
-#define HX509_VHN_F_ALLOW_NO_MATCH 1
+
+/**
+ * Verify that the certificate is allowed to be used for the hostname
+ * and address.
+ *
+ * @param context A hx509 context.
+ * @param cert the certificate to match with
+ * @param flags Flags to modify the behavior:
+ * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
+ * @param type type of hostname:
+ * - HX509_HN_HOSTNAME for plain hostname.
+ * - HX509_HN_DNSSRV for DNS SRV names.
+ * @param hostname the hostname to check
+ * @param sa address of the host
+ * @param sa_size length of address
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
int
hx509_verify_hostname(hx509_context context,
@@ -1984,6 +2422,19 @@ _hx509_set_cert_attribute(hx509_context context,
return 0;
}
+/**
+ * Get an external attribute for the certificate, examples are
+ * friendly name and id.
+ *
+ * @param cert hx509 certificate object to search
+ * @param oid an oid to search for.
+ *
+ * @return an hx509_cert_attribute, only valid as long as the
+ * certificate is referenced.
+ *
+ * @ingroup hx509_cert
+ */
+
hx509_cert_attribute
hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
{
@@ -1994,6 +2445,17 @@ hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
return NULL;
}
+/**
+ * Set the friendly name on the certificate.
+ *
+ * @param cert The certificate to set the friendly name on
+ * @param name Friendly name.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
int
hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
{
@@ -2005,6 +2467,16 @@ hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
return 0;
}
+/**
+ * Get friendly name of the certificate.
+ *
+ * @param cert cert to get the friendly name from.
+ *
+ * @return an friendly name or NULL if there is. The friendly name is
+ * only valid as long as the certificate is referenced.
+ *
+ * @ingroup hx509_cert
+ */
const char *
hx509_cert_get_friendly_name(hx509_cert cert)
@@ -2056,6 +2528,17 @@ _hx509_query_clear(hx509_query *q)
memset(q, 0, sizeof(*q));
}
+/**
+ * Allocate an query controller. Free using hx509_query_free().
+ *
+ * @param context A hx509 context.
+ * @param q return pointer to a hx509_query.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
int
hx509_query_alloc(hx509_context context, hx509_query **q)
{
@@ -2065,6 +2548,17 @@ hx509_query_alloc(hx509_context context, hx509_query **q)
return 0;
}
+/**
+ * Set match options for the hx509 query controller.
+ *
+ * @param q query controller.
+ * @param option options to control the query controller.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
void
hx509_query_match_option(hx509_query *q, hx509_query_option option)
{
@@ -2087,6 +2581,19 @@ hx509_query_match_option(hx509_query *q, hx509_query_option option)
}
}
+/**
+ * Set the issuer and serial number of match in the query
+ * controller. The function make copies of the isser and serial number.
+ *
+ * @param q a hx509 query controller
+ * @param issuer issuer to search for
+ * @param serialNumber the serialNumber of the issuer.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
int
hx509_query_match_issuer_serial(hx509_query *q,
const Name *issuer,
@@ -2123,6 +2630,16 @@ hx509_query_match_issuer_serial(hx509_query *q,
return 0;
}
+/**
+ * Set the query controller to match on a friendly name
+ *
+ * @param q a hx509 query controller.
+ * @param name a friendly name to match on
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
int
hx509_query_match_friendly_name(hx509_query *q, const char *name)
@@ -2136,6 +2653,63 @@ hx509_query_match_friendly_name(hx509_query *q, const char *name)
return 0;
}
+/**
+ * Set the query controller to require an one specific EKU (extended
+ * key usage). Any previous EKU matching is overwitten. If NULL is
+ * passed in as the eku, the EKU requirement is reset.
+ *
+ * @param q a hx509 query controller.
+ * @param eku an EKU to match on.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
+int
+hx509_query_match_eku(hx509_query *q, const heim_oid *eku)
+{
+ int ret;
+
+ if (eku == NULL) {
+ if (q->eku) {
+ der_free_oid(q->eku);
+ free(q->eku);
+ q->eku = NULL;
+ }
+ q->match &= ~HX509_QUERY_MATCH_EKU;
+ } else {
+ if (q->eku) {
+ der_free_oid(q->eku);
+ } else {
+ q->eku = calloc(1, sizeof(*q->eku));
+ if (q->eku == NULL)
+ return ENOMEM;
+ }
+ ret = der_copy_oid(eku, q->eku);
+ if (ret) {
+ free(q->eku);
+ q->eku = NULL;
+ return ret;
+ }
+ q->match |= HX509_QUERY_MATCH_EKU;
+ }
+ return 0;
+}
+
+/**
+ * Set the query controller to match using a specific match function.
+ *
+ * @param q a hx509 query controller.
+ * @param func function to use for matching, if the argument is NULL,
+ * the match function is removed.
+ * @param ctx context passed to the function.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
int
hx509_query_match_cmp_func(hx509_query *q,
int (*func)(void *, hx509_cert),
@@ -2150,24 +2724,36 @@ hx509_query_match_cmp_func(hx509_query *q,
return 0;
}
+/**
+ * Free the query controller.
+ *
+ * @param context A hx509 context.
+ * @param q a pointer to the query controller.
+ *
+ * @ingroup hx509_cert
+ */
void
hx509_query_free(hx509_context context, hx509_query *q)
{
+ if (q == NULL)
+ return;
+
if (q->serial) {
der_free_heim_integer(q->serial);
free(q->serial);
- q->serial = NULL;
}
if (q->issuer_name) {
free_Name(q->issuer_name);
free(q->issuer_name);
- q->issuer_name = NULL;
}
- if (q) {
- free(q->friendlyname);
- memset(q, 0, sizeof(*q));
+ if (q->eku) {
+ der_free_oid(q->eku);
+ free(q->eku);
}
+ if (q->friendlyname)
+ free(q->friendlyname);
+ memset(q, 0, sizeof(*q));
free(q);
}
@@ -2175,6 +2761,7 @@ int
_hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
{
Certificate *c = _hx509_get_cert(cert);
+ int ret, diff;
_hx509_query_statistic(context, 1, q);
@@ -2190,17 +2777,20 @@ _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert
&& der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
return 0;
- if ((q->match & HX509_QUERY_MATCH_ISSUER_NAME)
- && _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name) != 0)
- return 0;
+ if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) {
+ ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff);
+ if (ret || diff)
+ return 0;
+ }
- if ((q->match & HX509_QUERY_MATCH_SUBJECT_NAME)
- && _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name) != 0)
- return 0;
+ if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) {
+ ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff);
+ if (ret || diff)
+ return 0;
+ }
if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
SubjectKeyIdentifier si;
- int ret;
ret = _hx509_find_extension_subject_key_id(c, &si);
if (ret == 0) {
@@ -2264,14 +2854,13 @@ _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert
return 0;
}
if (q->match & HX509_QUERY_MATCH_FUNCTION) {
- int ret = (*q->cmp_func)(q->cmp_func_ctx, cert);
+ ret = (*q->cmp_func)(q->cmp_func_ctx, cert);
if (ret != 0)
return 0;
}
if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
heim_octet_string os;
- int ret;
os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
os.length =
@@ -2296,12 +2885,26 @@ _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert
return 0;
}
+ /* If an EKU is required, check the cert for it. */
+ if ((q->match & HX509_QUERY_MATCH_EKU) &&
+ hx509_cert_check_eku(context, cert, q->eku, 0))
+ return 0;
+
if (q->match & ~HX509_QUERY_MASK)
return 0;
return 1;
}
+/**
+ * Set a statistic file for the query statistics.
+ *
+ * @param context A hx509 context.
+ * @param fn statistics file name
+ *
+ * @ingroup hx509_cert
+ */
+
void
hx509_query_statistic_file(hx509_context context, const char *fn)
{
@@ -2362,6 +2965,16 @@ stat_sort(const void *a, const void *b)
return be->stats - ae->stats;
}
+/**
+ * Unparse the statistics file and print the result on a FILE descriptor.
+ *
+ * @param context A hx509 context.
+ * @param printtype tyep to print
+ * @param out the FILE to write the data on.
+ *
+ * @ingroup hx509_cert
+ */
+
void
hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
{
@@ -2435,6 +3048,20 @@ hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
multiqueries, totalqueries);
}
+/**
+ * Check the extended key usage on the hx509 certificate.
+ *
+ * @param context A hx509 context.
+ * @param cert A hx509 context.
+ * @param eku the EKU to check for
+ * @param allow_any_eku if the any EKU is set, allow that to be a
+ * substitute.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
int
hx509_cert_check_eku(hx509_context context, hx509_cert cert,
const heim_oid *eku, int allow_any_eku)
@@ -2511,6 +3138,19 @@ _hx509_cert_get_eku(hx509_context context,
return 0;
}
+/**
+ * Encodes the hx509 certificate as a DER encode binary.
+ *
+ * @param context A hx509 context.
+ * @param c the certificate to encode.
+ * @param os the encode certificate, set to NULL, 0 on case of
+ * error. Free the returned structure with hx509_xfree().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_cert
+ */
+
int
hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
{
@@ -2522,8 +3162,11 @@ hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
_hx509_get_cert(c), &size, ret);
- if (ret)
+ if (ret) {
+ os->data = NULL;
+ os->length = 0;
return ret;
+ }
if (os->length != size)
_hx509_abort("internal ASN.1 encoder error");
@@ -2550,3 +3193,16 @@ _hx509_abort(const char *fmt, ...)
abort();
}
+/**
+ * Free a data element allocated in the library.
+ *
+ * @param ptr data to be freed.
+ *
+ * @ingroup hx509_misc
+ */
+
+void
+hx509_xfree(void *ptr)
+{
+ free(ptr);
+}
diff --git a/source4/heimdal/lib/hx509/cms.c b/source4/heimdal/lib/hx509/cms.c
index 30f364060d0..80bcaac6c98 100644
--- a/source4/heimdal/lib/hx509/cms.c
+++ b/source4/heimdal/lib/hx509/cms.c
@@ -32,11 +32,46 @@
*/
#include "hx_locl.h"
-RCSID("$Id: cms.c 21319 2007-06-25 19:46:52Z lha $");
+RCSID("$Id: cms.c 22327 2007-12-15 04:49:37Z lha $");
+
+/**
+ * @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.
+ *
+ *
+ * See the library functions here: @ref hx509_cms
+ */
#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 +87,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;
- }
- ci.content->data = malloc(buf->length);
- if (ci.content->data == 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;
}
- 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 +112,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 out 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,
@@ -267,6 +318,27 @@ find_CMSIdentifier(hx509_context context,
return 0;
}
+/**
+ * Decode and unencrypt EnvelopedData.
+ *
+ * Extract data and parameteres from from the EnvelopedData. Also
+ * supports using detached EnvelopedData.
+ *
+ * @param context A hx509 context.
+ * @param certs Certificate that can decrypt the EnvelopedData
+ * encryption key.
+ * @param flags HX509_CMS_UE flags to control the behavior.
+ * @param data pointer the structure the contains the DER/BER encoded
+ * EnvelopedData stucture.
+ * @param length length of the data that data point to.
+ * @param encryptedContent in case of detached signature, this
+ * contains the actual encrypted data, othersize its should be NULL.
+ * @param contentType output type oid, should be freed with der_free_oid().
+ * @param content the data, free with der_free_octet_string().
+ *
+ * @ingroup hx509_cms
+ */
+
int
hx509_cms_unenvelope(hx509_context context,
hx509_certs certs,
@@ -335,11 +407,6 @@ hx509_cms_unenvelope(hx509_context context,
ri = &ed.recipientInfos.val[i];
- /* ret = search_keyset(ri,
- * PRIVATE_KEY,
- * ki->keyEncryptionAlgorithm.algorithm);
- */
-
ret = find_CMSIdentifier(context, &ri->rid, certs, &cert,
HX509_QUERY_PRIVATE_KEY|findflags);
if (ret)
@@ -444,6 +511,29 @@ out:
return ret;
}
+/**
+ * Encrypt end encode EnvelopedData.
+ *
+ * Encrypt and encode EnvelopedData. The data is encrypted with a
+ * random key and the the random key is encrypted with the
+ * certificates private key. This limits what private key type can be
+ * used to RSA.
+ *
+ * @param context A hx509 context.
+ * @param flags flags to control the behavior, no flags today
+ * @param cert Certificate to encrypt the EnvelopedData encryption key
+ * with.
+ * @param data pointer the data to encrypt.
+ * @param length length of the data that data point to.
+ * @param encryption_type Encryption cipher to use for the bulk data,
+ * use NULL to get default.
+ * @param contentType type of the data that is encrypted
+ * @param content the output of the function,
+ * free with der_free_octet_string().
+ *
+ * @ingroup hx509_cms
+ */
+
int
hx509_cms_envelope_1(hx509_context context,
int flags,
@@ -637,13 +727,31 @@ find_attribute(const CMSAttributes *attr, const heim_oid *oid)
return NULL;
}
+/**
+ * Decode SignedData and verify that the signature is correct.
+ *
+ * @param context A hx509 context.
+ * @param ctx a hx509 version context
+ * @param data
+ * @param length length of the data that data point to.
+ * @param signedContent
+ * @param pool certificate pool to build certificates paths.
+ * @param contentType free with der_free_oid()
+ * @param content the output of the function, free with
+ * der_free_octet_string().
+ * @param signer_certs list of the cerficates used to sign this
+ * request, free with hx509_certs_free().
+ *
+ * @ingroup hx509_cms
+ */
+
int
hx509_cms_verify_signed(hx509_context context,
hx509_verify_ctx ctx,
const void *data,
size_t length,
const heim_octet_string *signedContent,
- hx509_certs store,
+ hx509_certs pool,
heim_oid *contentType,
heim_octet_string *content,
hx509_certs *signer_certs)
@@ -701,8 +809,8 @@ hx509_cms_verify_signed(hx509_context context,
if (ret)
goto out;
- if (store) {
- ret = hx509_certs_merge(context, certs, store);
+ if (pool) {
+ ret = hx509_certs_merge(context, certs, pool);
if (ret)
goto out;
}
@@ -946,6 +1054,29 @@ add_one_attribute(Attribute **attr,
return 0;
}
+/**
+ * Decode SignedData and verify that the signature is correct.
+ *
+ * @param context A hx509 context.
+ * @param flags
+ * @param eContentType the type of the data.
+ * @param data data to sign
+ * @param length length of the data that data point to.
+ * @param digest_alg digest algorithm to use, use NULL to get the
+ * default or the peer determined algorithm.
+ * @param cert certificate to use for sign the data.
+ * @param peer info about the peer the message to send the message to,
+ * like what digest algorithm to use.
+ * @param anchors trust anchors that the client will use, used to
+ * polulate the certificates included in the message
+ * @param pool certificates to use in try to build the path to the
+ * trust anchors.
+ * @param signed_data the output of the function, free with
+ * der_free_octet_string().
+ *
+ * @ingroup hx509_cms
+ */
+
int
hx509_cms_create_signed_1(hx509_context context,
int flags,
@@ -1050,7 +1181,7 @@ hx509_cms_create_signed_1(hx509_context context,
}
/*
- * If its not pkcs7-data send signedAttributes
+ * If it isn't pkcs7-data send signedAttributes
*/
if (der_heim_oid_cmp(eContentType, oid_id_pkcs7_data()) != 0) {
diff --git a/source4/heimdal/lib/hx509/crypto.c b/source4/heimdal/lib/hx509/crypto.c
index d86300bd586..e0f00ad7b45 100644
--- a/source4/heimdal/lib/hx509/crypto.c
+++ b/source4/heimdal/lib/hx509/crypto.c
@@ -32,7 +32,7 @@
*/
#include "hx_locl.h"
-RCSID("$Id: crypto.c 21318 2007-06-25 19:46:32Z lha $");
+RCSID("$Id: crypto.c 22435 2008-01-14 20:53:56Z lha $");
struct hx509_crypto;
@@ -64,6 +64,7 @@ struct hx509_private_key_ops {
int (*generate_private_key)(hx509_context,
struct hx509_generate_private_context *,
hx509_private_key);
+ BIGNUM *(*get_internal)(hx509_context, hx509_private_key, const char *);
int (*handle_alg)(const hx509_private_key,
const AlgorithmIdentifier *,
enum crypto_op_type);
@@ -115,6 +116,9 @@ struct signature_alg {
#define SIG_PUBLIC_SIG 0x200
#define SIG_SECRET 0x400
+#define RA_RSA_USES_DIGEST_INFO 0x1000000
+
+
int (*verify_signature)(hx509_context context,
const struct signature_alg *,
const Certificate *,
@@ -248,43 +252,57 @@ rsa_verify_signature(hx509_context context,
}
if (retsize > tosize)
_hx509_abort("internal rsa decryption failure: ret > tosize");
- ret = decode_DigestInfo(to, retsize, &di, &size);
- free(to);
- if (ret) {
- goto out;
- }
- /* Check for extra data inside the sigature */
- if (size != retsize) {
- ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
- hx509_set_error_string(context, 0, ret, "size from decryption mismatch");
- goto out;
- }
+ if (sig_alg->flags & RA_RSA_USES_DIGEST_INFO) {
- if (sig_alg->digest_oid &&
- der_heim_oid_cmp(&di.digestAlgorithm.algorithm,
- (*sig_alg->digest_oid)()) != 0)
- {
- ret = HX509_CRYPTO_OID_MISMATCH;
- hx509_set_error_string(context, 0, ret, "object identifier in RSA sig mismatch");
- goto out;
- }
+ ret = decode_DigestInfo(to, retsize, &di, &size);
+ free(to);
+ if (ret) {
+ goto out;
+ }
+
+ /* Check for extra data inside the sigature */
+ if (size != retsize) {
+ ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
+ hx509_set_error_string(context, 0, ret, "size from decryption mismatch");
+ goto out;
+ }
+
+ if (sig_alg->digest_oid &&
+ der_heim_oid_cmp(&di.digestAlgorithm.algorithm,
+ (*sig_alg->digest_oid)()) != 0)
+ {
+ ret = HX509_CRYPTO_OID_MISMATCH;
+ hx509_set_error_string(context, 0, ret, "object identifier in RSA sig mismatch");
+ goto out;
+ }
+
+ /* verify that the parameters are NULL or the NULL-type */
+ if (di.digestAlgorithm.parameters != NULL &&
+ (di.digestAlgorithm.parameters->length != 2 ||
+ memcmp(di.digestAlgorithm.parameters->data, "\x05\x00", 2) != 0))
+ {
+ ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
+ hx509_set_error_string(context, 0, ret, "Extra parameters inside RSA signature");
+ goto out;
+ }
- /* verify that the parameters are NULL or the NULL-type */
- if (di.digestAlgorithm.parameters != NULL &&
- (di.digestAlgorithm.parameters->length != 2 ||
- memcmp(di.digestAlgorithm.parameters->data, "\x05\x00", 2) != 0))
- {
- ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
- hx509_set_error_string(context, 0, ret, "Extra parameters inside RSA signature");
- goto out;
+ ret = _hx509_verify_signature(context,
+ NULL,
+ &di.digestAlgorithm,
+ data,
+ &di.digest);
+ } else {
+ if (retsize != data->length ||
+ memcmp(to, data->data, retsize) != 0)
+ {
+ ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
+ hx509_set_error_string(context, 0, ret, "RSA Signature incorrect");
+ goto out;
+ }
+ free(to);
}
- ret = _hx509_verify_signature(context,
- NULL,
- &di.digestAlgorithm,
- data,
- &di.digest);
out:
free_DigestInfo(&di);
RSA_free(rsa);
@@ -303,7 +321,6 @@ rsa_create_signature(hx509_context context,
const AlgorithmIdentifier *digest_alg;
heim_octet_string indata;
const heim_oid *sig_oid;
- DigestInfo di;
size_t size;
int ret;
@@ -324,6 +341,8 @@ rsa_create_signature(hx509_context context,
digest_alg = hx509_signature_sha1();
} else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_rsaEncryption()) == 0) {
digest_alg = hx509_signature_sha1();
+ } else if (der_heim_oid_cmp(sig_oid, oid_id_heim_rsa_pkcs1_x509()) == 0) {
+ digest_alg = NULL;
} else
return HX509_ALG_NOT_SUPP;
@@ -335,29 +354,34 @@ rsa_create_signature(hx509_context context,
}
}
- memset(&di, 0, sizeof(di));
+ if (digest_alg) {
+ DigestInfo di;
+ memset(&di, 0, sizeof(di));
- ret = _hx509_create_signature(context,
- NULL,
- digest_alg,
- data,
- &di.digestAlgorithm,
- &di.digest);
- if (ret)
- return ret;
- ASN1_MALLOC_ENCODE(DigestInfo,
- indata.data,
- indata.length,
- &di,
- &size,
- ret);
- free_DigestInfo(&di);
- if (ret) {
- hx509_set_error_string(context, 0, ret, "out of memory");
- return ret;
+ ret = _hx509_create_signature(context,
+ NULL,
+ digest_alg,
+ data,
+ &di.digestAlgorithm,
+ &di.digest);
+ if (ret)
+ return ret;
+ ASN1_MALLOC_ENCODE(DigestInfo,
+ indata.data,
+ indata.length,
+ &di,
+ &size,
+ ret);
+ free_DigestInfo(&di);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "out of memory");
+ return ret;
+ }
+ if (indata.length != size)
+ _hx509_abort("internal ASN.1 encoder error");
+ } else {
+ indata = *data;
}
- if (indata.length != size)
- _hx509_abort("internal ASN.1 encoder error");
sig->length = RSA_size(signer->private_key.rsa);
sig->data = malloc(sig->length);
@@ -371,7 +395,8 @@ rsa_create_signature(hx509_context context,
sig->data,
signer->private_key.rsa,
RSA_PKCS1_PADDING);
- der_free_octet_string(&indata);
+ if (indata.data != data->data)
+ der_free_octet_string(&indata);
if (ret <= 0) {
ret = HX509_CMS_FAILED_CREATE_SIGATURE;
hx509_set_error_string(context, 0, ret,
@@ -517,6 +542,18 @@ rsa_private_key_export(hx509_context context,
return 0;
}
+static BIGNUM *
+rsa_get_internal(hx509_context context, hx509_private_key key, const char *type)
+{
+ if (strcasecmp(type, "rsa-modulus") == 0) {
+ return BN_dup(key->private_key.rsa->n);
+ } else if (strcasecmp(type, "rsa-exponent") == 0) {
+ return BN_dup(key->private_key.rsa->e);
+ } else
+ return NULL;
+}
+
+
static hx509_private_key_ops rsa_private_key_ops = {
"RSA PRIVATE KEY",
@@ -524,7 +561,8 @@ static hx509_private_key_ops rsa_private_key_ops = {
rsa_private_key2SPKI,
rsa_private_key_export,
rsa_private_key_import,
- rsa_generate_private_key
+ rsa_generate_private_key,
+ rsa_get_internal
};
@@ -833,13 +871,24 @@ md2_verify_signature(hx509_context context,
return 0;
}
+static const struct signature_alg heim_rsa_pkcs1_x509 = {
+ "rsa-pkcs1-x509",
+ oid_id_heim_rsa_pkcs1_x509,
+ hx509_signature_rsa_pkcs1_x509,
+ oid_id_pkcs1_rsaEncryption,
+ NULL,
+ PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG,
+ rsa_verify_signature,
+ rsa_create_signature
+};
+
static const struct signature_alg pkcs1_rsa_sha1_alg = {
"rsa",
oid_id_pkcs1_rsaEncryption,
hx509_signature_rsa_with_sha1,
oid_id_pkcs1_rsaEncryption,
NULL,
- PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG,
+ PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG,
rsa_verify_signature,
rsa_create_signature
};
@@ -850,7 +899,7 @@ static const struct signature_alg rsa_with_sha256_alg = {
hx509_signature_rsa_with_sha256,
oid_id_pkcs1_rsaEncryption,
oid_id_sha256,
- PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG,
+ PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG,
rsa_verify_signature,
rsa_create_signature
};
@@ -861,7 +910,7 @@ static const struct signature_alg rsa_with_sha1_alg = {
hx509_signature_rsa_with_sha1,
oid_id_pkcs1_rsaEncryption,
oid_id_secsig_sha_1,
- PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG,
+ PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG,
rsa_verify_signature,
rsa_create_signature
};
@@ -872,7 +921,7 @@ static const struct signature_alg rsa_with_md5_alg = {
hx509_signature_rsa_with_md5,
oid_id_pkcs1_rsaEncryption,
oid_id_rsa_digest_md5,
- PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG,
+ PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG,
rsa_verify_signature,
rsa_create_signature
};
@@ -883,7 +932,7 @@ static const struct signature_alg rsa_with_md2_alg = {
hx509_signature_rsa_with_md2,
oid_id_pkcs1_rsaEncryption,
oid_id_rsa_digest_md2,
- PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG,
+ PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG,
rsa_verify_signature,
rsa_create_signature
};
@@ -952,7 +1001,7 @@ static const struct signature_alg *sig_algs[] = {
&pkcs1_rsa_sha1_alg,
&rsa_with_md5_alg,
&rsa_with_md2_alg,
- &pkcs1_rsa_sha1_alg,
+ &heim_rsa_pkcs1_x509,
&dsa_sha1_alg,
&sha256_alg,
&sha1_alg,
@@ -1423,6 +1472,11 @@ const AlgorithmIdentifier _hx509_signature_rsa_data = {
{ 7, rk_UNCONST(rsa_oid) }, NULL
};
+static const unsigned rsa_pkcs1_x509_oid[] ={ 1, 2, 752, 43, 16, 1 };
+const AlgorithmIdentifier _hx509_signature_rsa_pkcs1_x509_data = {
+ { 6, rk_UNCONST(rsa_pkcs1_x509_oid) }, NULL
+};
+
static const unsigned des_rsdi_ede3_cbc_oid[] ={ 1, 2, 840, 113549, 3, 7 };
const AlgorithmIdentifier _hx509_des_rsdi_ede3_cbc_oid = {
{ 6, rk_UNCONST(des_rsdi_ede3_cbc_oid) }, NULL
@@ -1491,6 +1545,10 @@ hx509_signature_rsa(void)
{ return &_hx509_signature_rsa_data; }
const AlgorithmIdentifier *
+hx509_signature_rsa_pkcs1_x509(void)
+{ return &_hx509_signature_rsa_pkcs1_x509_data; }
+
+const AlgorithmIdentifier *
hx509_crypto_des_rsdi_ede3_cbc(void)
{ return &_hx509_des_rsdi_ede3_cbc_oid; }
@@ -1597,6 +1655,16 @@ _hx509_private_key_exportable(hx509_private_key key)
return 1;
}
+BIGNUM *
+_hx509_private_key_get_internal(hx509_context context,
+ hx509_private_key key,
+ const char *type)
+{
+ if (key->ops->get_internal == NULL)
+ return NULL;
+ return (*key->ops->get_internal)(context, key, type);
+}
+
int
_hx509_private_key_export(hx509_context context,
const hx509_private_key key,
diff --git a/source4/heimdal/lib/hx509/env.c b/source4/heimdal/lib/hx509/env.c
index 4cb2f9f4b17..f868c22488c 100644
--- a/source4/heimdal/lib/hx509/env.c
+++ b/source4/heimdal/lib/hx509/env.c
@@ -32,7 +32,13 @@
*/
#include "hx_locl.h"
-RCSID("$Id: env.c 19878 2007-01-13 00:58:39Z lha $");
+RCSID("$Id: env.c 22349 2007-12-26 19:32:49Z lha $");
+
+/**
+ * @page page_env Hx509 enviroment functions
+ *
+ * See the library functions here: @ref hx509_env
+ */
struct hx509_env {
struct {
@@ -42,6 +48,17 @@ struct hx509_env {
size_t len;
};
+/**
+ * Allocate a new hx509_env container object.
+ *
+ * @param context A hx509 context.
+ * @param env return a hx509_env structure, free with hx509_env_free().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_env
+ */
+
int
hx509_env_init(hx509_context context, hx509_env *env)
{
@@ -53,6 +70,19 @@ hx509_env_init(hx509_context context, hx509_env *env)
return 0;
}
+/**
+ * Add a new key/value pair to the hx509_env.
+ *
+ * @param context A hx509 context.
+ * @param env enviroment to add the enviroment variable too.
+ * @param key key to add
+ * @param value value to add
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_env
+ */
+
int
hx509_env_add(hx509_context context, hx509_env env,
const char *key, const char *value)
@@ -80,6 +110,19 @@ hx509_env_add(hx509_context context, hx509_env env,
return 0;
}
+/**
+ * Search the hx509_env for a key.
+ *
+ * @param context A hx509 context.
+ * @param env enviroment to add the enviroment variable too.
+ * @param key key to search for.
+ * @param len length of key.
+ *
+ * @return the value if the key is found, NULL otherwise.
+ *
+ * @ingroup hx509_env
+ */
+
const char *
hx509_env_lfind(hx509_context context, hx509_env env,
const char *key, size_t len)
@@ -94,6 +137,13 @@ hx509_env_lfind(hx509_context context, hx509_env env,
return NULL;
}
+/**
+ * Free an hx509_env enviroment context.
+ *
+ * @param env the enviroment to free.
+ *
+ * @ingroup hx509_env
+ */
void
hx509_env_free(hx509_env *env)
diff --git a/source4/heimdal/lib/hx509/error.c b/source4/heimdal/lib/hx509/error.c
index 9f3a0148732..25119ed2883 100644
--- a/source4/heimdal/lib/hx509/error.c
+++ b/source4/heimdal/lib/hx509/error.c
@@ -32,7 +32,13 @@
*/
#include "hx_locl.h"
-RCSID("$Id: error.c 20912 2007-06-05 03:53:52Z lha $");
+RCSID("$Id: error.c 22332 2007-12-17 01:03:22Z lha $");
+
+/**
+ * @page page_error Hx509 error reporting functions
+ *
+ * See the library functions here: @ref hx509_error
+ */
struct hx509_error_data {
hx509_error next;
@@ -51,6 +57,14 @@ free_error_string(hx509_error msg)
}
}
+/**
+ * Resets the error strings the hx509 context.
+ *
+ * @param context A hx509 context.
+ *
+ * @ingroup hx509_error
+ */
+
void
hx509_clear_error_string(hx509_context context)
{
@@ -58,6 +72,20 @@ hx509_clear_error_string(hx509_context context)
context->error = NULL;
}
+/**
+ * Add an error message to the hx509 context.
+ *
+ * @param context A hx509 context.
+ * @param flags
+ * - HX509_ERROR_APPEND appends the error string to the old messages
+ (code is updated).
+ * @param code error code related to error message
+ * @param fmt error message format
+ * @param ap arguments to error message format
+ *
+ * @ingroup hx509_error
+ */
+
void
hx509_set_error_stringv(hx509_context context, int flags, int code,
const char *fmt, va_list ap)
@@ -86,6 +114,20 @@ hx509_set_error_stringv(hx509_context context, int flags, int code,
}
}
+/**
+ * See hx509_set_error_stringv().
+ *
+ * @param context A hx509 context.
+ * @param flags
+ * - HX509_ERROR_APPEND appends the error string to the old messages
+ (code is updated).
+ * @param code error code related to error message
+ * @param fmt error message format
+ * @param ... arguments to error message format
+ *
+ * @ingroup hx509_error
+ */
+
void
hx509_set_error_string(hx509_context context, int flags, int code,
const char *fmt, ...)
@@ -97,6 +139,17 @@ hx509_set_error_string(hx509_context context, int flags, int code,
va_end(ap);
}
+/**
+ * Get an error string from context associated with error_code.
+ *
+ * @param context A hx509 context.
+ * @param error_code Get error message for this error code.
+ *
+ * @return error string, free with hx509_free_error_string().
+ *
+ * @ingroup hx509_error
+ */
+
char *
hx509_get_error_string(hx509_context context, int error_code)
{
@@ -125,6 +178,32 @@ hx509_get_error_string(hx509_context context, int error_code)
return rk_strpoolcollect(p);
}
+/**
+ * Free error string returned by hx509_get_error_string().
+ *
+ * @param str error string to free.
+ *
+ * @ingroup hx509_error
+ */
+
+void
+hx509_free_error_string(char *str)
+{
+ free(str);
+}
+
+/**
+ * Print error message and fatally exit from error code
+ *
+ * @param context A hx509 context.
+ * @param exit_code exit() code from process.
+ * @param error_code Error code for the reason to exit.
+ * @param fmt format string with the exit message.
+ * @param ... argument to format string.
+ *
+ * @ingroup hx509_error
+ */
+
void
hx509_err(hx509_context context, int exit_code,
int error_code, const char *fmt, ...)
diff --git a/source4/heimdal/lib/hx509/hx509-private.h b/source4/heimdal/lib/hx509/hx509-private.h
index acbc3218c64..be36c07421e 100644
--- a/source4/heimdal/lib/hx509/hx509-private.h
+++ b/source4/heimdal/lib/hx509/hx509-private.h
@@ -9,6 +9,11 @@
#endif
int
+_hx509_AlgorithmIdentifier_cmp (
+ const AlgorithmIdentifier */*p*/,
+ const AlgorithmIdentifier */*q*/);
+
+int
_hx509_Certificate_cmp (
const Certificate */*p*/,
const Certificate */*q*/);
@@ -269,12 +274,14 @@ _hx509_match_keys (
int
_hx509_name_cmp (
const Name */*n1*/,
- const Name */*n2*/);
+ const Name */*n2*/,
+ int */*c*/);
int
_hx509_name_ds_cmp (
const DirectoryString */*ds1*/,
- const DirectoryString */*ds2*/);
+ const DirectoryString */*ds2*/,
+ int */*diff*/);
int
_hx509_name_from_Name (
@@ -314,6 +321,14 @@ _hx509_pbe_decrypt (
const heim_octet_string */*econtent*/,
heim_octet_string */*content*/);
+int
+_hx509_pbe_encrypt (
+ hx509_context /*context*/,
+ hx509_lock /*lock*/,
+ const AlgorithmIdentifier */*ai*/,
+ const heim_octet_string */*content*/,
+ heim_octet_string */*econtent*/);
+
void
_hx509_pi_printf (
int (*/*func*/)(void *, const char *),
@@ -344,6 +359,12 @@ _hx509_private_key_exportable (hx509_private_key /*key*/);
int
_hx509_private_key_free (hx509_private_key */*key*/);
+BIGNUM *
+_hx509_private_key_get_internal (
+ hx509_context /*context*/,
+ hx509_private_key /*key*/,
+ const char */*type*/);
+
int
_hx509_private_key_init (
hx509_private_key */*key*/,
@@ -415,11 +436,35 @@ void
_hx509_request_free (hx509_request */*req*/);
int
+_hx509_request_get_SubjectPublicKeyInfo (
+ hx509_context /*context*/,
+ hx509_request /*req*/,
+ SubjectPublicKeyInfo */*key*/);
+
+int
+_hx509_request_get_name (
+ hx509_context /*context*/,
+ hx509_request /*req*/,
+ hx509_name */*name*/);
+
+int
_hx509_request_init (
hx509_context /*context*/,
hx509_request */*req*/);
int
+_hx509_request_parse (
+ hx509_context /*context*/,
+ const char */*path*/,
+ hx509_request */*req*/);
+
+int
+_hx509_request_print (
+ hx509_context /*context*/,
+ hx509_request /*req*/,
+ FILE */*f*/);
+
+int
_hx509_request_set_SubjectPublicKeyInfo (
hx509_context /*context*/,
hx509_request /*req*/,
@@ -438,6 +483,9 @@ _hx509_request_to_pkcs10 (
const hx509_private_key /*signer*/,
heim_octet_string */*request*/);
+hx509_revoke_ctx
+_hx509_revoke_ref (hx509_revoke_ctx /*ctx*/);
+
int
_hx509_set_cert_attribute (
hx509_context /*context*/,
diff --git a/source4/heimdal/lib/hx509/hx509-protos.h b/source4/heimdal/lib/hx509/hx509-protos.h
index 71fb29d59dd..3e297424cc9 100644
--- a/source4/heimdal/lib/hx509/hx509-protos.h
+++ b/source4/heimdal/lib/hx509/hx509-protos.h
@@ -183,6 +183,7 @@ hx509_cert_cmp (
int
hx509_cert_find_subjectAltName_otherName (
+ hx509_context /*context*/,
hx509_cert /*cert*/,
const heim_oid */*oid*/,
hx509_octet_string_list */*list*/);
@@ -192,9 +193,16 @@ hx509_cert_free (hx509_cert /*cert*/);
int
hx509_cert_get_SPKI (
+ hx509_context /*context*/,
hx509_cert /*p*/,
SubjectPublicKeyInfo */*spki*/);
+int
+hx509_cert_get_SPKI_AlgorithmIdentifier (
+ hx509_context /*context*/,
+ hx509_cert /*p*/,
+ AlgorithmIdentifier */*alg*/);
+
hx509_cert_attribute
hx509_cert_get_attribute (
hx509_cert /*cert*/,
@@ -231,6 +239,9 @@ hx509_cert_get_subject (
hx509_name */*name*/);
int
+hx509_cert_have_private_key (hx509_cert /*p*/);
+
+int
hx509_cert_init (
hx509_context /*context*/,
const Certificate */*c*/,
@@ -305,7 +316,7 @@ int
hx509_certs_iter (
hx509_context /*context*/,
hx509_certs /*certs*/,
- int (*/*fn*/)(hx509_context, void *, hx509_cert),
+ int (*/*func*/)(hx509_context, void *, hx509_cert),
void */*ctx*/);
int
@@ -402,7 +413,7 @@ hx509_cms_verify_signed (
const void */*data*/,
size_t /*length*/,
const heim_octet_string */*signedContent*/,
- hx509_certs /*store*/,
+ hx509_certs /*pool*/,
heim_oid */*contentType*/,
heim_octet_string */*content*/,
hx509_certs */*signer_certs*/);
@@ -581,6 +592,9 @@ hx509_err (
...);
void
+hx509_free_error_string (char */*str*/);
+
+void
hx509_free_octet_string_list (hx509_octet_string_list */*list*/);
int
@@ -652,6 +666,11 @@ hx509_lock_set_prompter (
void */*data*/);
int
+hx509_name_binary (
+ const hx509_name /*name*/,
+ heim_octet_string */*os*/);
+
+int
hx509_name_cmp (
hx509_name /*n1*/,
hx509_name /*n2*/);
@@ -685,12 +704,6 @@ hx509_name_to_Name (
Name */*to*/);
int
-hx509_name_to_der_name (
- const hx509_name /*name*/,
- void **/*data*/,
- size_t */*length*/);
-
-int
hx509_name_to_string (
const hx509_name /*name*/,
char **/*str*/);
@@ -783,13 +796,6 @@ hx509_pem_write (
size_t /*size*/);
void
-hx509_print_func (
- hx509_vprint_func /*func*/,
- void */*ctx*/,
- const char */*fmt*/,
- ...);
-
-void
hx509_print_stdout (
void */*ctx*/,
const char */*fmt*/,
@@ -815,6 +821,11 @@ hx509_query_match_cmp_func (
void */*ctx*/);
int
+hx509_query_match_eku (
+ hx509_query */*q*/,
+ const heim_oid */*eku*/);
+
+int
hx509_query_match_friendly_name (
hx509_query */*q*/,
const char */*name*/);
@@ -902,6 +913,9 @@ const AlgorithmIdentifier *
hx509_signature_rsa (void);
const AlgorithmIdentifier *
+hx509_signature_rsa_pkcs1_x509 (void);
+
+const AlgorithmIdentifier *
hx509_signature_rsa_with_md2 (void);
const AlgorithmIdentifier *
@@ -1030,6 +1044,9 @@ hx509_verify_signature (
const heim_octet_string */*data*/,
const heim_octet_string */*sig*/);
+void
+hx509_xfree (void */*ptr*/);
+
#ifdef __cplusplus
}
#endif
diff --git a/source4/heimdal/lib/hx509/hx509.h b/source4/heimdal/lib/hx509/hx509.h
index 2f22cedfbc8..be02f634749 100644
--- a/source4/heimdal/lib/hx509/hx509.h
+++ b/source4/heimdal/lib/hx509/hx509.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*/
-/* $Id: hx509.h 21310 2007-06-25 18:26:06Z lha $ */
+/* $Id: hx509.h 22464 2008-01-16 14:24:50Z lha $ */
typedef struct hx509_cert_attribute_data *hx509_cert_attribute;
typedef struct hx509_cert_data *hx509_cert;
@@ -56,6 +56,10 @@ typedef struct hx509_crl *hx509_crl;
typedef void (*hx509_vprint_func)(void *, const char *, va_list);
enum {
+ HX509_VHN_F_ALLOW_NO_MATCH = 1
+};
+
+enum {
HX509_VALIDATE_F_VALIDATE = 1,
HX509_VALIDATE_F_VERBOSE = 2
};
@@ -107,6 +111,7 @@ typedef enum {
/* flags to hx509_certs_init */
#define HX509_CERTS_CREATE 0x01
+#define HX509_CERTS_UNPROTECT_ALL 0x02
/* flags to hx509_set_error_string */
#define HX509_ERROR_APPEND 0x01
diff --git a/source4/heimdal/lib/hx509/hx509_err.et b/source4/heimdal/lib/hx509/hx509_err.et
index 90f3b3d907d..8fc5cb8f2f7 100644
--- a/source4/heimdal/lib/hx509/hx509_err.et
+++ b/source4/heimdal/lib/hx509/hx509_err.et
@@ -3,7 +3,7 @@
#
# This might look like a com_err file, but is not
#
-id "$Id: hx509_err.et 20807 2007-06-03 03:11:20Z lha $"
+id "$Id: hx509_err.et 22329 2007-12-15 05:13:14Z lha $"
error_table hx
prefix HX509
@@ -72,7 +72,7 @@ prefix HX509
error_code CRL_USED_BEFORE_TIME, "CRL used before it became valid"
error_code CRL_USED_AFTER_TIME, "CRL used after it became invalid"
error_code CRL_INVALID_FORMAT, "CRL have invalid format"
-error_code CRL_CERT_REVOKED, "Certificate is included in CRL"
+error_code CERT_REVOKED, "Certificate is revoked"
error_code REVOKE_STATUS_MISSING, "No revoke status found for certificates"
error_code CRL_UNKNOWN_EXTENSION, "Unknown extension"
error_code REVOKE_WRONG_DATA, "Got wrong CRL/OCSP data from server"
diff --git a/source4/heimdal/lib/hx509/hx_locl.h b/source4/heimdal/lib/hx509/hx_locl.h
index 145bfcc006d..6d89167bfcb 100644
--- a/source4/heimdal/lib/hx509/hx_locl.h
+++ b/source4/heimdal/lib/hx509/hx_locl.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*/
-/* $Id: hx_locl.h 21083 2007-06-13 02:11:19Z lha $ */
+/* $Id: hx_locl.h 22538 2008-01-27 13:05:47Z lha $ */
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -128,7 +128,8 @@ struct hx509_query_data {
#define HX509_QUERY_MATCH_FUNCTION 0x080000
#define HX509_QUERY_MATCH_KEY_HASH_SHA1 0x100000
#define HX509_QUERY_MATCH_TIME 0x200000
-#define HX509_QUERY_MASK 0x3fffff
+#define HX509_QUERY_MATCH_EKU 0x400000
+#define HX509_QUERY_MASK 0x7fffff
Certificate *subject;
Certificate *certificate;
heim_integer *serial;
@@ -142,6 +143,7 @@ struct hx509_query_data {
void *cmp_func_ctx;
heim_octet_string *keyhash_sha1;
time_t timenow;
+ heim_oid *eku;
};
struct hx509_keyset_ops {
diff --git a/source4/heimdal/lib/hx509/keyset.c b/source4/heimdal/lib/hx509/keyset.c
index 7da5705a802..2fcff7b03b3 100644
--- a/source4/heimdal/lib/hx509/keyset.c
+++ b/source4/heimdal/lib/hx509/keyset.c
@@ -32,7 +32,31 @@
*/
#include "hx_locl.h"
-RCSID("$Id: keyset.c 21140 2007-06-18 21:24:19Z lha $");
+RCSID("$Id: keyset.c 22466 2008-01-16 14:26:35Z lha $");
+
+/**
+ * @page page_keyset Certificate store operations
+ *
+ * Type of certificates store:
+ * - MEMORY
+ * In memory based format. Doesnt support storing.
+ * - FILE
+ * FILE supports raw DER certicates and PEM certicates. When PEM is
+ * used the file can contain may certificates and match private
+ * keys. Support storing the certificates. DER format only supports
+ * on certificate and no private key.
+ * - PEM-FILE
+ * Same as FILE, defaulting to PEM encoded certificates.
+ * - PEM-FILE
+ * Same as FILE, defaulting to DER encoded certificates.
+ * - PKCS11
+ * - PKCS12
+ * - DIR
+ * - KEYCHAIN
+ * Apple Mac OS X KeyChain backed keychain object.
+ *
+ * See the library functions here: @ref hx509_keyset
+ */
struct hx509_certs_data {
int ref;
@@ -69,6 +93,22 @@ _hx509_ks_register(hx509_context context, struct hx509_keyset_ops *ops)
context->ks_num_ops++;
}
+/**
+ * Open or creates a new hx509 certificate store.
+ *
+ * @param context A hx509 context
+ * @param name name of the store, format is TYPE:type-specific-string,
+ * if NULL is used the MEMORY store is used.
+ * @param flags list of flags:
+ * - HX509_CERTS_CREATE create a new keystore of the specific TYPE.
+ * - HX509_CERTS_UNPROTECT_ALL fails if any private key failed to be extracted.
+ * @param lock a lock that unlocks the certificates store, use NULL to
+ * select no password/certifictes/prompt lock (see @ref page_lock).
+ * @param certs return pointer, free with hx509_certs_free().
+ *
+ * @ingroup hx509_keyset
+ */
+
int
hx509_certs_init(hx509_context context,
const char *name, int flags,
@@ -125,6 +165,21 @@ hx509_certs_init(hx509_context context,
return 0;
}
+/**
+ * Write the certificate store to stable storage.
+ *
+ * @param context A hx509 context.
+ * @param certs a certificate store to store.
+ * @param flags currently unused, use 0.
+ * @param lock a lock that unlocks the certificates store, use NULL to
+ * select no password/certifictes/prompt lock (see @ref page_lock).
+ *
+ * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION if
+ * the certificate store doesn't support the store operation.
+ *
+ * @ingroup hx509_keyset
+ */
+
int
hx509_certs_store(hx509_context context,
hx509_certs certs,
@@ -132,11 +187,11 @@ hx509_certs_store(hx509_context context,
hx509_lock lock)
{
if (certs->ops->store == NULL) {
- hx509_set_error_string(context, 0, EINVAL,
+ hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
"keystore if type %s doesn't support "
"store operation",
certs->ops->name);
- return EINVAL;
+ return HX509_UNSUPPORTED_OPERATION;
}
return (*certs->ops->store)(context, certs, certs->ops_data, flags, lock);
@@ -146,6 +201,8 @@ hx509_certs_store(hx509_context context,
hx509_certs
_hx509_certs_ref(hx509_certs certs)
{
+ if (certs == NULL)
+ return NULL;
if (certs->ref <= 0)
_hx509_abort("certs refcount <= 0");
certs->ref++;
@@ -154,6 +211,14 @@ _hx509_certs_ref(hx509_certs certs)
return certs;
}
+/**
+ * Free a certificate store.
+ *
+ * @param certs certificate store to free.
+ *
+ * @ingroup hx509_keyset
+ */
+
void
hx509_certs_free(hx509_certs *certs)
{
@@ -169,6 +234,21 @@ hx509_certs_free(hx509_certs *certs)
}
}
+/**
+ * Start the integration
+ *
+ * @param context a hx509 context.
+ * @param certs certificate store to iterate over
+ * @param cursor cursor that will keep track of progress, free with
+ * hx509_certs_end_seq().
+ *
+ * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION is
+ * returned if the certificate store doesn't support the iteration
+ * operation.
+ *
+ * @ingroup hx509_keyset
+ */
+
int
hx509_certs_start_seq(hx509_context context,
hx509_certs certs,
@@ -177,10 +257,10 @@ hx509_certs_start_seq(hx509_context context,
int ret;
if (certs->ops->iter_start == NULL) {
- hx509_set_error_string(context, 0, ENOENT,
+ hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
"Keyset type %s doesn't support iteration",
certs->ops->name);
- return ENOENT;
+ return HX509_UNSUPPORTED_OPERATION;
}
ret = (*certs->ops->iter_start)(context, certs, certs->ops_data, cursor);
@@ -190,6 +270,21 @@ hx509_certs_start_seq(hx509_context context,
return 0;
}
+/**
+ * Get next ceritificate from the certificate keystore pointed out by
+ * cursor.
+ *
+ * @param context a hx509 context.
+ * @param certs certificate store to iterate over.
+ * @param cursor cursor that keeps track of progress.
+ * @param cert return certificate next in store, NULL if the store
+ * contains no more certificates. Free with hx509_cert_free().
+ *
+ * @return Returns an hx509 error code.
+ *
+ * @ingroup hx509_keyset
+ */
+
int
hx509_certs_next_cert(hx509_context context,
hx509_certs certs,
@@ -200,6 +295,18 @@ hx509_certs_next_cert(hx509_context context,
return (*certs->ops->iter)(context, certs, certs->ops_data, cursor, cert);
}
+/**
+ * End the iteration over certificates.
+ *
+ * @param context a hx509 context.
+ * @param certs certificate store to iterate over.
+ * @param cursor cursor that will keep track of progress, freed.
+ *
+ * @return Returns an hx509 error code.
+ *
+ * @ingroup hx509_keyset
+ */
+
int
hx509_certs_end_seq(hx509_context context,
hx509_certs certs,
@@ -209,11 +316,26 @@ hx509_certs_end_seq(hx509_context context,
return 0;
}
+/**
+ * Iterate over all certificates in a keystore and call an function
+ * for each fo them.
+ *
+ * @param context a hx509 context.
+ * @param certs certificate store to iterate over.
+ * @param func function to call for each certificate. The function
+ * should return non-zero to abort the iteration, that value is passed
+ * back to te caller of hx509_certs_iter().
+ * @param ctx context variable that will passed to the function.
+ *
+ * @return Returns an hx509 error code.
+ *
+ * @ingroup hx509_keyset
+ */
int
hx509_certs_iter(hx509_context context,
hx509_certs certs,
- int (*fn)(hx509_context, void *, hx509_cert),
+ int (*func)(hx509_context, void *, hx509_cert),
void *ctx)
{
hx509_cursor cursor;
@@ -232,7 +354,7 @@ hx509_certs_iter(hx509_context context,
ret = 0;
break;
}
- ret = (*fn)(context, ctx, c);
+ ret = (*func)(context, ctx, c);
hx509_cert_free(c);
if (ret)
break;
@@ -243,6 +365,20 @@ hx509_certs_iter(hx509_context context,
return ret;
}
+
+/**
+ * Function to use to hx509_certs_iter() as a function argument, the
+ * ctx variable to hx509_certs_iter() should be a FILE file descriptor.
+ *
+ * @param context a hx509 context.
+ * @param ctx used by hx509_certs_iter().
+ * @param c a certificate
+ *
+ * @return Returns an hx509 error code.
+ *
+ * @ingroup hx509_keyset
+ */
+
int
hx509_ci_print_names(hx509_context context, void *ctx, hx509_cert c)
{
@@ -264,10 +400,20 @@ hx509_ci_print_names(hx509_context context, void *ctx, hx509_cert c)
return 0;
}
-/*
- * The receiving keyset `certsī will either increase reference counter
- * of the `certī or make a deep copy, either way, the caller needs to
- * free the `certī itself.
+/**
+ * Add a certificate to the certificiate store.
+ *
+ * The receiving keyset certs will either increase reference counter
+ * of the cert or make a deep copy, either way, the caller needs to
+ * free the cert itself.
+ *
+ * @param context a hx509 context.
+ * @param certs certificate store to add the certificate to.
+ * @param cert certificate to add.
+ *
+ * @return Returns an hx509 error code.
+ *
+ * @ingroup hx509_keyset
*/
int
@@ -283,6 +429,20 @@ hx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert)
return (*certs->ops->add)(context, certs, certs->ops_data, cert);
}
+/**
+ * Find a certificate matching the query.
+ *
+ * @param context a hx509 context.
+ * @param certs certificate store to search.
+ * @param q query allocated with @ref hx509_query functions.
+ * @param r return certificate (or NULL on error), should be freed
+ * with hx509_cert_free().
+ *
+ * @return Returns an hx509 error code.
+ *
+ * @ingroup hx509_keyset
+ */
+
int
hx509_certs_find(hx509_context context,
hx509_certs certs,
@@ -335,6 +495,19 @@ certs_merge_func(hx509_context context, void *ctx, hx509_cert c)
return hx509_certs_add(context, (hx509_certs)ctx, c);
}
+/**
+ * Merge a certificate store into another. The from store is keep
+ * intact.
+ *
+ * @param context a hx509 context.
+ * @param to the store to merge into.
+ * @param from the store to copy the object from.
+ *
+ * @return Returns an hx509 error code.
+ *
+ * @ingroup hx509_keyset
+ */
+
int
hx509_certs_merge(hx509_context context, hx509_certs to, hx509_certs from)
{
@@ -343,6 +516,21 @@ hx509_certs_merge(hx509_context context, hx509_certs to, hx509_certs from)
return hx509_certs_iter(context, from, certs_merge_func, to);
}
+/**
+ * Same a hx509_certs_merge() but use a lock and name to describe the
+ * from source.
+ *
+ * @param context a hx509 context.
+ * @param to the store to merge into.
+ * @param lock a lock that unlocks the certificates store, use NULL to
+ * select no password/certifictes/prompt lock (see @ref page_lock).
+ * @param name name of the source store
+ *
+ * @return Returns an hx509 error code.
+ *
+ * @ingroup hx509_keyset
+ */
+
int
hx509_certs_append(hx509_context context,
hx509_certs to,
@@ -360,6 +548,18 @@ hx509_certs_append(hx509_context context,
return ret;
}
+/**
+ * Get one random certificate from the certificate store.
+ *
+ * @param context a hx509 context.
+ * @param certs a certificate store to get the certificate from.
+ * @param c return certificate, should be freed with hx509_cert_free().
+ *
+ * @return Returns an hx509 error code.
+ *
+ * @ingroup hx509_keyset
+ */
+
int
hx509_get_one_cert(hx509_context context, hx509_certs certs, hx509_cert *c)
{
@@ -388,6 +588,21 @@ certs_info_stdio(void *ctx, const char *str)
return 0;
}
+/**
+ * Print some info about the certificate store.
+ *
+ * @param context a hx509 context.
+ * @param certs certificate store to print information about.
+ * @param func function that will get each line of the information, if
+ * NULL is used the data is printed on a FILE descriptor that should
+ * be passed in ctx, if ctx also is NULL, stdout is used.
+ * @param ctx parameter to func.
+ *
+ * @return Returns an hx509 error code.
+ *
+ * @ingroup hx509_keyset
+ */
+
int
hx509_certs_info(hx509_context context,
hx509_certs certs,
diff --git a/source4/heimdal/lib/hx509/ks_file.c b/source4/heimdal/lib/hx509/ks_file.c
index 269afd03b10..87b97af401c 100644
--- a/source4/heimdal/lib/hx509/ks_file.c
+++ b/source4/heimdal/lib/hx509/ks_file.c
@@ -32,7 +32,7 @@
*/
#include "hx_locl.h"
-RCSID("$Id: ks_file.c 21314 2007-06-25 18:45:07Z lha $");
+RCSID("$Id: ks_file.c 22465 2008-01-16 14:25:24Z lha $");
typedef enum { USE_PEM, USE_DER } outformat;
@@ -289,19 +289,25 @@ struct pem_formats {
};
+struct pem_ctx {
+ int flags;
+ struct hx509_collector *c;
+};
+
static int
pem_func(hx509_context context, const char *type,
const hx509_pem_header *header,
const void *data, size_t len, void *ctx)
{
- struct hx509_collector *c = ctx;
- int ret, j;
+ struct pem_ctx *pem_ctx = (struct pem_ctx*)ctx;
+ int ret = 0, j;
for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) {
const char *q = formats[j].name;
if (strcasecmp(type, q) == 0) {
- ret = (*formats[j].func)(context, NULL, c, header, data, len);
- break;
+ ret = (*formats[j].func)(context, NULL, pem_ctx->c, header, data, len);
+ if (ret == 0)
+ break;
}
}
if (j == sizeof(formats)/sizeof(formats[0])) {
@@ -310,6 +316,8 @@ pem_func(hx509_context context, const char *type,
"Found no matching PEM format for %s", type);
return ret;
}
+ if (ret && (pem_ctx->flags & HX509_CERTS_UNPROTECT_ALL))
+ return ret;
return 0;
}
@@ -324,9 +332,12 @@ file_init_common(hx509_context context,
{
char *p, *pnext;
struct ks_file *f = NULL;
- struct hx509_collector *c = NULL;
hx509_private_key *keys = NULL;
int ret;
+ struct pem_ctx pem_ctx;
+
+ pem_ctx.flags = flags;
+ pem_ctx.c = NULL;
*data = NULL;
@@ -361,7 +372,7 @@ file_init_common(hx509_context context,
return 0;
}
- ret = _hx509_collector_alloc(context, lock, &c);
+ ret = _hx509_collector_alloc(context, lock, &pem_ctx.c);
if (ret)
goto out;
@@ -381,7 +392,7 @@ file_init_common(hx509_context context,
goto out;
}
- ret = hx509_pem_read(context, f, pem_func, c);
+ ret = hx509_pem_read(context, f, pem_func, &pem_ctx);
fclose(f);
if (ret != 0 && ret != HX509_PARSING_KEY_FAILED)
goto out;
@@ -397,7 +408,7 @@ file_init_common(hx509_context context,
}
for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
- ret = (*formats[i].func)(context, p, c, NULL, ptr, length);
+ ret = (*formats[i].func)(context, p, pem_ctx.c, NULL, ptr, length);
if (ret == 0)
break;
}
@@ -407,11 +418,11 @@ file_init_common(hx509_context context,
}
}
- ret = _hx509_collector_collect_certs(context, c, &f->certs);
+ ret = _hx509_collector_collect_certs(context, pem_ctx.c, &f->certs);
if (ret)
goto out;
- ret = _hx509_collector_collect_private_keys(context, c, &keys);
+ ret = _hx509_collector_collect_private_keys(context, pem_ctx.c, &keys);
if (ret == 0) {
int i;
@@ -428,8 +439,9 @@ out:
free(f->fn);
free(f);
}
- if (c)
- _hx509_collector_free(c);
+ if (pem_ctx.c)
+ _hx509_collector_free(pem_ctx.c);
+
return ret;
}
diff --git a/source4/heimdal/lib/hx509/ks_keychain.c b/source4/heimdal/lib/hx509/ks_keychain.c
index 33c4d6774b3..f8181975d9d 100644
--- a/source4/heimdal/lib/hx509/ks_keychain.c
+++ b/source4/heimdal/lib/hx509/ks_keychain.c
@@ -32,17 +32,19 @@
*/
#include "hx_locl.h"
-RCSID("$Id: ks_keychain.c 21097 2007-06-16 07:00:49Z lha $");
+RCSID("$Id: ks_keychain.c 22084 2007-11-16 20:12:30Z lha $");
#ifdef HAVE_FRAMEWORK_SECURITY
#include <Security/Security.h>
-/* Missing function decls */
+/* Missing function decls in pre Leopard */
+#ifdef NEED_SECKEYGETCSPHANDLE_PROTO
OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *);
OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG,
int, const CSSM_ACCESS_CREDENTIALS **);
#define kSecCredentialTypeDefault 0
+#endif
static int
@@ -50,7 +52,7 @@ getAttribute(SecKeychainItemRef itemRef, SecItemAttr item,
SecKeychainAttributeList **attrs)
{
SecKeychainAttributeInfo attrInfo;
- uint32 attrFormat = 0;
+ UInt32 attrFormat = 0;
OSStatus ret;
*attrs = NULL;
@@ -408,7 +410,7 @@ keychain_iter(hx509_context context,
{
SecKeychainAttributeList *attrs = NULL;
SecKeychainAttributeInfo attrInfo;
- uint32 attrFormat[1] = { 0 };
+ UInt32 attrFormat[1] = { 0 };
SecKeychainItemRef itemRef;
SecItemAttr item[1];
struct iter *iter = cursor;
diff --git a/source4/heimdal/lib/hx509/ks_p11.c b/source4/heimdal/lib/hx509/ks_p11.c
index e3066bbcfac..0d7c312c724 100644
--- a/source4/heimdal/lib/hx509/ks_p11.c
+++ b/source4/heimdal/lib/hx509/ks_p11.c
@@ -32,7 +32,7 @@
*/
#include "hx_locl.h"
-RCSID("$Id: ks_p11.c 21387 2007-06-28 08:53:45Z lha $");
+RCSID("$Id: ks_p11.c 22071 2007-11-14 20:04:50Z lha $");
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
@@ -403,7 +403,7 @@ p11_get_session(hx509_context context,
* prompter or known to work pin code.
*
* This code is very conversative and only uses the prompter in
- * the hx509_lock, the reason is that its bad to try many
+ * the hx509_lock, the reason is that it's bad to try many
* passwords on a pkcs11 token, it might lock up and have to be
* unlocked by a administrator.
*
diff --git a/source4/heimdal/lib/hx509/lock.c b/source4/heimdal/lib/hx509/lock.c
index de326f2e2de..e835aee35af 100644
--- a/source4/heimdal/lib/hx509/lock.c
+++ b/source4/heimdal/lib/hx509/lock.c
@@ -32,7 +32,13 @@
*/
#include "hx_locl.h"
-RCSID("$Id: lock.c 18452 2006-10-14 09:41:05Z lha $");
+RCSID("$Id: lock.c 22327 2007-12-15 04:49:37Z lha $");
+
+/**
+ * @page page_lock Locking and unlocking certificates and encrypted data.
+ *
+ * See the library functions here: @ref hx509_lock
+ */
struct hx509_lock_data {
struct _hx509_password password;
diff --git a/source4/heimdal/lib/hx509/name.c b/source4/heimdal/lib/hx509/name.c
index 5198633b1e5..3f0806ddc01 100644
--- a/source4/heimdal/lib/hx509/name.c
+++ b/source4/heimdal/lib/hx509/name.c
@@ -32,17 +32,39 @@
*/
#include "hx_locl.h"
-RCSID("$Id: name.c 20891 2007-06-04 22:51:41Z lha $");
+#include <wind.h>
+RCSID("$Id: name.c 22583 2008-02-11 20:46:21Z lha $");
-/*
- * 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.
+ *
+ * See the library functions here: @ref hx509_name
*/
static const struct {
const char *n;
const heim_oid *(*o)(void);
+ wind_profile_flags flags;
} no[] = {
{ "C", oid_id_at_countryName },
{ "CN", oid_id_at_commonName },
@@ -153,6 +175,18 @@ stringtooid(const char *name, size_t len, heim_oid *oid)
return ret;
}
+/**
+ * Convert the hx509 name object into a printable string.
+ * The resulting string should be freed with free().
+ *
+ * @param name name to print
+ * @param str the string to return
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_name
+ */
+
int
hx509_name_to_string(const hx509_name name, char **str)
{
@@ -247,82 +281,185 @@ _hx509_Name_to_string(const Name *n, char **str)
return 0;
}
-/*
- * XXX this function is broken, it needs to compare code points, not
- * bytes.
- */
+#define COPYCHARARRAY(_ds,_el,_l,_n) \
+ (_l) = strlen(_ds->u._el); \
+ (_n) = malloc((_l) * sizeof((_n)[0])); \
+ if ((_n) == NULL) \
+ return ENOMEM; \
+ for (i = 0; i < (_l); i++) \
+ (_n)[i] = _ds->u._el[i]
-int
-_hx509_name_ds_cmp(const DirectoryString *ds1, const DirectoryString *ds2)
+
+#define COPYVALARRAY(_ds,_el,_l,_n) \
+ (_l) = _ds->u._el.length; \
+ (_n) = malloc((_l) * sizeof((_n)[0])); \
+ if ((_n) == NULL) \
+ return ENOMEM; \
+ for (i = 0; i < (_l); i++) \
+ (_n)[i] = _ds->u._el.data[i]
+
+#define COPYVOIDARRAY(_ds,_el,_l,_n) \
+ (_l) = _ds->u._el.length; \
+ (_n) = malloc((_l) * sizeof((_n)[0])); \
+ if ((_n) == NULL) \
+ return ENOMEM; \
+ for (i = 0; i < (_l); i++) \
+ (_n)[i] = ((unsigned char *)_ds->u._el.data)[i]
+
+
+
+static int
+dsstringprep(const DirectoryString *ds, uint32_t **rname, size_t *rlen)
{
- int c;
+ wind_profile_flags flags = 0;
+ size_t i, len;
+ int ret;
+ uint32_t *name;
- c = ds1->element - ds2->element;
- if (c)
- return c;
+ *rname = NULL;
+ *rlen = 0;
- switch(ds1->element) {
+ switch(ds->element) {
case choice_DirectoryString_ia5String:
- c = strcmp(ds1->u.ia5String, ds2->u.ia5String);
- break;
- case choice_DirectoryString_teletexString:
- c = der_heim_octet_string_cmp(&ds1->u.teletexString,
- &ds2->u.teletexString);
+ COPYCHARARRAY(ds, ia5String, len, name);
break;
case choice_DirectoryString_printableString:
- c = strcasecmp(ds1->u.printableString, ds2->u.printableString);
+ flags = WIND_PROFILE_LDAP_CASE_EXACT_ATTRIBUTE;
+ COPYCHARARRAY(ds, printableString, len, name);
break;
- case choice_DirectoryString_utf8String:
- c = strcmp(ds1->u.utf8String, ds2->u.utf8String);
+ case choice_DirectoryString_teletexString:
+ COPYVOIDARRAY(ds, teletexString, len, name);
+ break;
+ case choice_DirectoryString_bmpString:
+ COPYVALARRAY(ds, bmpString, len, name);
break;
case choice_DirectoryString_universalString:
- c = der_heim_universal_string_cmp(&ds1->u.universalString,
- &ds2->u.universalString);
+ COPYVALARRAY(ds, universalString, len, name);
break;
- case choice_DirectoryString_bmpString:
- c = der_heim_bmp_string_cmp(&ds1->u.bmpString,
- &ds2->u.bmpString);
+ case choice_DirectoryString_utf8String:
+ ret = wind_utf8ucs4_length(ds->u.utf8String, &len);
+ if (ret)
+ return ret;
+ name = malloc(len * sizeof(name[0]));
+ if (name == NULL)
+ return ENOMEM;
+ ret = wind_utf8ucs4(ds->u.utf8String, name, &len);
+ if (ret)
+ return ret;
break;
default:
- c = 1;
- break;
+ _hx509_abort("unknown directory type: %d", ds->element);
+ }
+
+ *rlen = len;
+ /* try a couple of times to get the length right, XXX gross */
+ for (i = 0; i < 4; i++) {
+ *rlen = *rlen * 2;
+ *rname = malloc(*rlen * sizeof((*rname)[0]));
+
+ ret = wind_stringprep(name, len, *rname, rlen,
+ WIND_PROFILE_LDAP|flags);
+ if (ret == WIND_ERR_OVERRUN) {
+ free(*rname);
+ *rname = NULL;
+ continue;
+ } else
+ break;
+ }
+ free(name);
+ if (ret) {
+ if (*rname)
+ free(*rname);
+ *rname = NULL;
+ *rlen = 0;
+ return ret;
+ }
+
+ return 0;
+}
+
+int
+_hx509_name_ds_cmp(const DirectoryString *ds1,
+ const DirectoryString *ds2,
+ int *diff)
+{
+ uint32_t *ds1lp, *ds2lp;
+ size_t ds1len, ds2len;
+ int ret;
+
+ ret = dsstringprep(ds1, &ds1lp, &ds1len);
+ if (ret)
+ return ret;
+ ret = dsstringprep(ds2, &ds2lp, &ds2len);
+ if (ret) {
+ free(ds1lp);
+ return ret;
}
- return c;
+
+ if (ds1len != ds2len)
+ *diff = ds1len - ds2len;
+ else
+ *diff = memcmp(ds1lp, ds2lp, ds1len * sizeof(ds1lp[0]));
+
+ free(ds1lp);
+ free(ds2lp);
+
+ return 0;
}
int
-_hx509_name_cmp(const Name *n1, const Name *n2)
+_hx509_name_cmp(const Name *n1, const Name *n2, int *c)
{
- int i, j, c;
+ int ret, i, j;
- c = n1->u.rdnSequence.len - n2->u.rdnSequence.len;
- if (c)
- return c;
+ *c = n1->u.rdnSequence.len - n2->u.rdnSequence.len;
+ if (*c)
+ return 0;
for (i = 0 ; i < n1->u.rdnSequence.len; i++) {
- c = n1->u.rdnSequence.val[i].len - n2->u.rdnSequence.val[i].len;
- if (c)
- return c;
+ *c = n1->u.rdnSequence.val[i].len - n2->u.rdnSequence.val[i].len;
+ if (*c)
+ return 0;
for (j = 0; j < n1->u.rdnSequence.val[i].len; j++) {
- c = der_heim_oid_cmp(&n1->u.rdnSequence.val[i].val[j].type,
- &n1->u.rdnSequence.val[i].val[j].type);
- if (c)
- return c;
+ *c = der_heim_oid_cmp(&n1->u.rdnSequence.val[i].val[j].type,
+ &n1->u.rdnSequence.val[i].val[j].type);
+ if (*c)
+ return 0;
- c = _hx509_name_ds_cmp(&n1->u.rdnSequence.val[i].val[j].value,
- &n2->u.rdnSequence.val[i].val[j].value);
- if (c)
- return c;
+ ret = _hx509_name_ds_cmp(&n1->u.rdnSequence.val[i].val[j].value,
+ &n2->u.rdnSequence.val[i].val[j].value,
+ c);
+ if (ret)
+ return ret;
+ if (*c)
+ return 0;
}
}
+ *c = 0;
return 0;
}
+/**
+ * Compare to hx509 name object, useful for sorting.
+ *
+ * @param n1 a hx509 name object.
+ * @param n2 a hx509 name object.
+ *
+ * @return 0 the objects are the same, returns > 0 is n2 is "larger"
+ * then n2, < 0 if n1 is "smaller" then n2.
+ *
+ * @ingroup hx509_name
+ */
+
int
hx509_name_cmp(hx509_name n1, hx509_name n2)
{
- return _hx509_name_cmp(&n1->der_name, &n2->der_name);
+ int ret, diff;
+ ret = _hx509_name_cmp(&n1->der_name, &n2->der_name, &diff);
+ if (ret)
+ return ret;
+ return diff;
}
@@ -341,19 +478,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,
@@ -400,6 +524,18 @@ _hx509_name_modify(hx509_context context,
return 0;
}
+/**
+ * Parse a string into a hx509 name object.
+ *
+ * @param context A hx509 context.
+ * @param str a string to parse.
+ * @param name the resulting object, NULL in case of error.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_name
+ */
+
int
hx509_parse_name(hx509_context context, const char *str, hx509_name *name)
{
@@ -492,6 +628,18 @@ out:
return HX509_NAME_MALFORMED;
}
+/**
+ * Copy a hx509 name object.
+ *
+ * @param context A hx509 cotext.
+ * @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_copy(hx509_context context, const hx509_name from, hx509_name *to)
{
@@ -509,6 +657,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)
{
@@ -521,6 +680,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,
@@ -539,6 +711,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];
@@ -615,6 +788,13 @@ hx509_name_expand(hx509_context context,
return 0;
}
+/**
+ * Free a hx509 name object, upond return *name will be NULL.
+ *
+ * @param name a hx509 name object to be freed.
+ *
+ * @ingroup hx509_name
+ */
void
hx509_name_free(hx509_name *name)
@@ -625,37 +805,61 @@ hx509_name_free(hx509_name *name)
*name = NULL;
}
+/**
+ * Convert a DER encoded name info a string.
+ *
+ * @param data data to a DER/BER encoded name
+ * @param length length of data
+ * @param str the resulting string, is NULL on failure.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @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 os data to a DER encoded name, free the resulting octet
+ * string with hx509_xfree(os->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)
+hx509_name_binary(const hx509_name name, heim_octet_string *os)
{
size_t size;
int ret;
- ASN1_MALLOC_ENCODE(Name, *data, *length, &name->der_name, &size, ret);
+ ASN1_MALLOC_ENCODE(Name, os->data, os->length, &name->der_name, &size, ret);
if (ret)
return ret;
- if (*length != size)
+ if (os->length != size)
_hx509_abort("internal ASN.1 encoder error");
return 0;
}
-
int
_hx509_unparse_Name(const Name *aname, char **str)
{
@@ -671,12 +875,33 @@ _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)
{
return name->der_name.u.rdnSequence.len == 0;
}
+/**
+ * Unparse the hx509 name in name into a string.
+ *
+ * @param name the name to print
+ * @param str an allocated string returns the name in string form
+ *
+ * @return An hx509 error code, see krb5_get_error_string().
+ *
+ * @ingroup hx509_name
+ */
+
int
hx509_general_name_unparse(GeneralName *name, char **str)
{
diff --git a/source4/heimdal/lib/hx509/peer.c b/source4/heimdal/lib/hx509/peer.c
index e90f8f34b06..eb0ecd2bdef 100644
--- a/source4/heimdal/lib/hx509/peer.c
+++ b/source4/heimdal/lib/hx509/peer.c
@@ -32,7 +32,27 @@
*/
#include "hx_locl.h"
-RCSID("$Id: peer.c 21481 2007-07-10 16:33:23Z lha $");
+RCSID("$Id: peer.c 22345 2007-12-26 19:03:51Z lha $");
+
+/**
+ * @page page_peer Hx509 crypto selecting functions
+ *
+ * Peer info structures are used togeter with hx509_crypto_select() to
+ * select the best avaible crypto algorithm to use.
+ *
+ * See the library functions here: @ref hx509_peer
+ */
+
+/**
+ * Allocate a new peer info structure an init it to default values.
+ *
+ * @param context A hx509 context.
+ * @param peer return an allocated peer, free with hx509_peer_info_free().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_peer
+ */
int
hx509_peer_info_alloc(hx509_context context, hx509_peer_info *peer)
@@ -59,6 +79,14 @@ free_cms_alg(hx509_peer_info peer)
}
}
+/**
+ * Free a peer info structure.
+ *
+ * @param peer peer info to be freed.
+ *
+ * @ingroup hx509_peer
+ */
+
void
hx509_peer_info_free(hx509_peer_info peer)
{
@@ -71,6 +99,17 @@ hx509_peer_info_free(hx509_peer_info peer)
free(peer);
}
+/**
+ * Set the certificate that remote peer is using.
+ *
+ * @param peer peer info to update
+ * @param cert cerificate of the remote peer.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_peer
+ */
+
int
hx509_peer_info_set_cert(hx509_peer_info peer,
hx509_cert cert)
@@ -81,6 +120,19 @@ hx509_peer_info_set_cert(hx509_peer_info peer,
return 0;
}
+/**
+ * Set the algorithms that the peer supports.
+ *
+ * @param context A hx509 context.
+ * @param peer the peer to set the new algorithms for
+ * @param val array of supported AlgorithmsIdentiers
+ * @param len length of array val.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_peer
+ */
+
int
hx509_peer_info_set_cms_algs(hx509_context context,
hx509_peer_info peer,
diff --git a/source4/heimdal/lib/hx509/print.c b/source4/heimdal/lib/hx509/print.c
index e6f71ea2ceb..c1594ff0476 100644
--- a/source4/heimdal/lib/hx509/print.c
+++ b/source4/heimdal/lib/hx509/print.c
@@ -32,8 +32,13 @@
*/
#include "hx_locl.h"
-RCSID("$Id: print.c 21381 2007-06-28 08:29:22Z lha $");
+RCSID("$Id: print.c 22538 2008-01-27 13:05:47Z lha $");
+/**
+ * @page page_print Hx509 printing functions
+ *
+ * See the library functions here: @ref hx509_print
+ */
struct hx509_validate_ctx_data {
int flags;
@@ -75,15 +80,31 @@ Time2string(const Time *T, char **str)
return 0;
}
+/**
+ * Helper function to print on stdout for:
+ * - hx509_oid_print(),
+ * - hx509_bitstring_print(),
+ * - hx509_validate_ctx_set_print().
+ *
+ * @param ctx the context to the print function. If the ctx is NULL,
+ * stdout is used.
+ * @param fmt the printing format.
+ * @param va the argumet list.
+ *
+ * @ingroup hx509_print
+ */
+
void
hx509_print_stdout(void *ctx, const char *fmt, va_list va)
{
FILE *f = ctx;
+ if (f == NULL)
+ f = stdout;
vfprintf(f, fmt, va);
}
-void
-hx509_print_func(hx509_vprint_func func, void *ctx, const char *fmt, ...)
+static void
+print_func(hx509_vprint_func func, void *ctx, const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
@@ -91,36 +112,82 @@ hx509_print_func(hx509_vprint_func func, void *ctx, const char *fmt, ...)
va_end(va);
}
+/**
+ * Print a oid to a string.
+ *
+ * @param oid oid to print
+ * @param str allocated string, free with hx509_xfree().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_print
+ */
+
int
hx509_oid_sprint(const heim_oid *oid, char **str)
{
return der_print_heim_oid(oid, '.', str);
}
+/**
+ * Print a oid using a hx509_vprint_func function. To print to stdout
+ * use hx509_print_stdout().
+ *
+ * @param oid oid to print
+ * @param func hx509_vprint_func to print with.
+ * @param ctx context variable to hx509_vprint_func function.
+ *
+ * @ingroup hx509_print
+ */
+
void
hx509_oid_print(const heim_oid *oid, hx509_vprint_func func, void *ctx)
{
char *str;
hx509_oid_sprint(oid, &str);
- hx509_print_func(func, ctx, "%s", str);
+ print_func(func, ctx, "%s", str);
free(str);
}
+/**
+ * Print a bitstring using a hx509_vprint_func function. To print to
+ * stdout use hx509_print_stdout().
+ *
+ * @param b bit string to print.
+ * @param func hx509_vprint_func to print with.
+ * @param ctx context variable to hx509_vprint_func function.
+ *
+ * @ingroup hx509_print
+ */
+
void
hx509_bitstring_print(const heim_bit_string *b,
hx509_vprint_func func, void *ctx)
{
int i;
- hx509_print_func(func, ctx, "\tlength: %d\n\t", b->length);
+ print_func(func, ctx, "\tlength: %d\n\t", b->length);
for (i = 0; i < (b->length + 7) / 8; i++)
- hx509_print_func(func, ctx, "%02x%s%s",
- ((unsigned char *)b->data)[i],
- i < (b->length - 7) / 8
- && (i == 0 || (i % 16) != 15) ? ":" : "",
- i != 0 && (i % 16) == 15 ?
- (i <= ((b->length + 7) / 8 - 2) ? "\n\t" : "\n"):"");
+ print_func(func, ctx, "%02x%s%s",
+ ((unsigned char *)b->data)[i],
+ i < (b->length - 7) / 8
+ && (i == 0 || (i % 16) != 15) ? ":" : "",
+ i != 0 && (i % 16) == 15 ?
+ (i <= ((b->length + 7) / 8 - 2) ? "\n\t" : "\n"):"");
}
+/**
+ * Print certificate usage for a certificate to a string.
+ *
+ * @param context A hx509 context.
+ * @param c a certificate print the keyusage for.
+ * @param s the return string with the keysage printed in to, free
+ * with hx509_xfree().
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_print
+ */
+
int
hx509_cert_keyusage_print(hx509_context context, hx509_cert c, char **s)
{
@@ -268,9 +335,6 @@ check_authorityKeyIdentifier(hx509_validate_ctx ctx,
status->haveAKI = 1;
check_Null(ctx, status, cf, e);
- status->haveSKI = 1;
- check_Null(ctx, status, cf, e);
-
ret = decode_AuthorityKeyIdentifier(e->extnValue.data,
e->extnValue.length,
&ai, &size);
@@ -298,6 +362,56 @@ check_authorityKeyIdentifier(hx509_validate_ctx ctx,
return 0;
}
+static int
+check_extKeyUsage(hx509_validate_ctx ctx,
+ struct cert_status *status,
+ enum critical_flag cf,
+ const Extension *e)
+{
+ ExtKeyUsage eku;
+ size_t size, i;
+ int ret;
+
+ check_Null(ctx, status, cf, e);
+
+ ret = decode_ExtKeyUsage(e->extnValue.data,
+ e->extnValue.length,
+ &eku, &size);
+ if (ret) {
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Decoding ExtKeyUsage failed: %d", ret);
+ return 1;
+ }
+ if (size != e->extnValue.length) {
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Padding data in EKU");
+ free_ExtKeyUsage(&eku);
+ return 1;
+ }
+ if (eku.len == 0) {
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "ExtKeyUsage length is 0");
+ return 1;
+ }
+
+ for (i = 0; i < eku.len; i++) {
+ char *str;
+ ret = der_print_heim_oid (&eku.val[i], '.', &str);
+ if (ret) {
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "\tEKU: failed to print oid %d", i);
+ free_ExtKeyUsage(&eku);
+ return 1;
+ }
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
+ "\teku-%d: %s\n", i, str);;
+ free(str);
+ }
+
+ free_ExtKeyUsage(&eku);
+
+ return 0;
+}
static int
check_pkinit_san(hx509_validate_ctx ctx, heim_any *a)
@@ -664,7 +778,7 @@ struct {
{ ext(policyMappings, Null), M_N_C },
{ ext(authorityKeyIdentifier, authorityKeyIdentifier), M_N_C },
{ ext(policyConstraints, Null), D_C },
- { ext(extKeyUsage, Null), D_C },
+ { ext(extKeyUsage, extKeyUsage), D_C },
{ ext(freshestCRL, Null), M_N_C },
{ ext(inhibitAnyPolicy, Null), M_C },
#undef ext
@@ -679,6 +793,18 @@ struct {
{ NULL }
};
+/**
+ * Allocate a hx509 validation/printing context.
+ *
+ * @param context A hx509 context.
+ * @param ctx a new allocated hx509 validation context, free with
+ * hx509_validate_ctx_free().
+
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_print
+ */
+
int
hx509_validate_ctx_init(hx509_context context, hx509_validate_ctx *ctx)
{
@@ -689,6 +815,18 @@ hx509_validate_ctx_init(hx509_context context, hx509_validate_ctx *ctx)
return 0;
}
+/**
+ * Set the printing functions for the validation context.
+ *
+ * @param ctx a hx509 valication context.
+ * @param func the printing function to usea.
+ * @param c the context variable to the printing function.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_print
+ */
+
void
hx509_validate_ctx_set_print(hx509_validate_ctx ctx,
hx509_vprint_func func,
@@ -698,18 +836,50 @@ hx509_validate_ctx_set_print(hx509_validate_ctx ctx,
ctx->ctx = c;
}
+/**
+ * Add flags to control the behaivor of the hx509_validate_cert()
+ * function.
+ *
+ * @param ctx A hx509 validation context.
+ * @param flags flags to add to the validation context.
+ *
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_print
+ */
+
void
hx509_validate_ctx_add_flags(hx509_validate_ctx ctx, int flags)
{
ctx->flags |= flags;
}
+/**
+ * Free an hx509 validate context.
+ *
+ * @param ctx the hx509 validate context to free.
+ *
+ * @ingroup hx509_print
+ */
+
void
hx509_validate_ctx_free(hx509_validate_ctx ctx)
{
free(ctx);
}
+/**
+ * Validate/Print the status of the certificate.
+ *
+ * @param context A hx509 context.
+ * @param ctx A hx509 validation context.
+ * @param cert the cerificate to validate/print.
+
+ * @return An hx509 error code, see hx509_get_error_string().
+ *
+ * @ingroup hx509_print
+ */
+
int
hx509_validate_cert(hx509_context context,
hx509_validate_ctx ctx,
diff --git a/source4/heimdal/lib/hx509/revoke.c b/source4/heimdal/lib/hx509/revoke.c
index ddcb17ee38d..2010f945f0e 100644
--- a/source4/heimdal/lib/hx509/revoke.c
+++ b/source4/heimdal/lib/hx509/revoke.c
@@ -31,14 +31,33 @@
* 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: revoke.c 21153 2007-06-18 21:55:46Z lha $");
+RCSID("$Id: revoke.c 22583 2008-02-11 20:46:21Z lha $");
struct revoke_crl {
char *path;
time_t last_modfied;
CRLCertificateList crl;
int verified;
+ int failed_verify;
};
struct revoke_ocsp {
@@ -51,6 +70,7 @@ struct revoke_ocsp {
struct hx509_revoke_ctx_data {
+ unsigned ref;
struct {
struct revoke_crl *val;
size_t len;
@@ -61,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)
{
@@ -68,6 +99,7 @@ hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx)
if (*ctx == NULL)
return ENOMEM;
+ (*ctx)->ref = 1;
(*ctx)->crls.len = 0;
(*ctx)->crls.val = NULL;
(*ctx)->ocsps.len = 0;
@@ -76,6 +108,19 @@ hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx)
return 0;
}
+hx509_revoke_ctx
+_hx509_revoke_ref(hx509_revoke_ctx ctx)
+{
+ if (ctx == NULL)
+ return NULL;
+ if (ctx->ref <= 0)
+ _hx509_abort("revoke ctx refcount <= 0");
+ ctx->ref++;
+ if (ctx->ref == 0)
+ _hx509_abort("revoke ctx refcount == 0");
+ return ctx;
+}
+
static void
free_ocsp(struct revoke_ocsp *ocsp)
{
@@ -85,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)
{
@@ -93,6 +146,11 @@ hx509_revoke_free(hx509_revoke_ctx *ctx)
if (ctx == NULL || *ctx == NULL)
return;
+ if ((*ctx)->ref <= 0)
+ _hx509_abort("revoke ctx refcount <= 0 on free");
+ if (--(*ctx)->ref > 0)
+ return;
+
for (i = 0; i < (*ctx)->crls.len; i++) {
free((*ctx)->crls.val[i].path);
free_CRLCertificateList(&(*ctx)->crls.val[i].crl);
@@ -150,7 +208,7 @@ verify_ocsp(hx509_context context,
/*
* If signer certificate isn't the CA certificate, lets check the
- * its the CA that signed the signer certificate and the OCSP EKU
+ * it is the CA that signed the signer certificate and the OCSP EKU
* is set.
*/
if (hx509_cert_cmp(signer, parent) != 0) {
@@ -324,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,
@@ -380,6 +450,7 @@ hx509_revoke_add_ocsp(hx509_context context,
static int
verify_crl(hx509_context context,
+ hx509_revoke_ctx ctx,
CRLCertificateList *crl,
time_t time_now,
hx509_certs certs,
@@ -391,52 +462,44 @@ verify_crl(hx509_context context,
int ret;
t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate);
- if (t > time_now)
+ if (t > time_now) {
+ hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME,
+ "CRL used before time");
return HX509_CRL_USED_BEFORE_TIME;
+ }
- if (crl->tbsCertList.nextUpdate == NULL)
+ if (crl->tbsCertList.nextUpdate == NULL) {
+ hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT,
+ "CRL missing nextUpdate");
return HX509_CRL_INVALID_FORMAT;
+ }
t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate);
- if (t < time_now)
+ if (t < time_now) {
+ hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME,
+ "CRL used after time");
return HX509_CRL_USED_AFTER_TIME;
+ }
_hx509_query_clear(&q);
- q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
- q.subject_name = &crl->tbsCertList.issuer;
+ /*
+ * If it's the signer have CRLSIGN bit set, use that as the signer
+ * cert for the certificate, otherwise, search for a certificate.
+ */
+ if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) {
+ signer = hx509_cert_ref(parent);
+ } else {
+ q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
+ q.match |= HX509_QUERY_KU_CRLSIGN;
+ q.subject_name = &crl->tbsCertList.issuer;
- ret = hx509_certs_find(context, certs, &q, &signer);
- if (ret)
- return ret;
-
- /* verify is parent or CRLsigner */
- if (hx509_cert_cmp(signer, parent) != 0) {
- Certificate *p = _hx509_get_cert(parent);
- Certificate *s = _hx509_get_cert(signer);
-
- ret = _hx509_cert_is_parent_cmp(s, p, 0);
- if (ret != 0) {
- ret = HX509_PARENT_NOT_CA;
- hx509_set_error_string(context, 0, ret, "Revoke CRL signer is "
- "doesn't have CA as signer certificate");
- goto out;
- }
-
- ret = _hx509_verify_signature_bitstring(context,
- p,
- &s->signatureAlgorithm,
- &s->tbsCertificate._save,
- &s->signatureValue);
+ ret = hx509_certs_find(context, certs, &q, &signer);
if (ret) {
hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
- "CRL signer signature invalid");
- goto out;
+ "Failed to find certificate for CRL");
+ return ret;
}
-
- ret = _hx509_check_key_usage(context, signer, 1 << 6, TRUE); /* crl */
- if (ret != 0)
- goto out;
}
ret = _hx509_verify_signature_bitstring(context,
@@ -450,6 +513,44 @@ verify_crl(hx509_context context,
goto out;
}
+ /*
+ * If signer is not CA cert, need to check revoke status of this
+ * CRL signing cert too, this include all parent CRL signer cert
+ * up to the root *sigh*, assume root at least hve CERTSIGN flag
+ * set.
+ */
+ while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) {
+ hx509_cert crl_parent;
+
+ _hx509_query_clear(&q);
+
+ q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
+ q.match |= HX509_QUERY_KU_CRLSIGN;
+ q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer;
+
+ ret = hx509_certs_find(context, certs, &q, &crl_parent);
+ if (ret) {
+ hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
+ "Failed to find parent of CRL signer");
+ goto out;
+ }
+
+ ret = hx509_revoke_verify(context,
+ ctx,
+ certs,
+ time_now,
+ signer,
+ crl_parent);
+ hx509_cert_free(signer);
+ signer = crl_parent;
+ if (ret) {
+ hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
+ "Failed to verify revoke "
+ "status of CRL signer");
+ goto out;
+ }
+ }
+
out:
hx509_cert_free(signer);
@@ -485,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,
@@ -537,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,
@@ -551,6 +681,8 @@ hx509_revoke_verify(hx509_context context,
unsigned long i, j, k;
int ret;
+ hx509_clear_error_string(context);
+
for (i = 0; i < ctx->ocsps.len; i++) {
struct revoke_ocsp *ocsp = &ctx->ocsps.val[i];
struct stat sb;
@@ -604,6 +736,10 @@ hx509_revoke_verify(hx509_context context,
case choice_OCSPCertStatus_good:
break;
case choice_OCSPCertStatus_revoked:
+ hx509_set_error_string(context, 0,
+ HX509_CERT_REVOKED,
+ "Certificate revoked by issuer in OCSP");
+ return HX509_CERT_REVOKED;
case choice_OCSPCertStatus_unknown:
continue;
}
@@ -613,7 +749,7 @@ hx509_revoke_verify(hx509_context context,
now + context->ocsp_time_diff)
continue;
- /* don't allow the next updte to be in the past */
+ /* don't allow the next update to be in the past */
if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) {
if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now)
continue;
@@ -627,11 +763,12 @@ hx509_revoke_verify(hx509_context context,
for (i = 0; i < ctx->crls.len; i++) {
struct revoke_crl *crl = &ctx->crls.val[i];
struct stat sb;
+ int diff;
/* check if cert.issuer == crls.val[i].crl.issuer */
ret = _hx509_name_cmp(&c->tbsCertificate.issuer,
- &crl->crl.tbsCertList.issuer);
- if (ret)
+ &crl->crl.tbsCertList.issuer, &diff);
+ if (ret || diff)
continue;
ret = stat(crl->path, &sb);
@@ -643,21 +780,32 @@ hx509_revoke_verify(hx509_context context,
free_CRLCertificateList(&crl->crl);
crl->crl = cl;
crl->verified = 0;
+ crl->failed_verify = 0;
}
}
+ if (crl->failed_verify)
+ continue;
/* verify signature in crl if not already done */
if (crl->verified == 0) {
- ret = verify_crl(context, &crl->crl, now, certs, parent_cert);
- if (ret)
- return ret;
+ ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert);
+ if (ret) {
+ crl->failed_verify = 1;
+ continue;
+ }
crl->verified = 1;
}
-
- if (crl->crl.tbsCertList.crlExtensions)
- for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++)
- if (crl->crl.tbsCertList.crlExtensions->val[j].critical)
+
+ if (crl->crl.tbsCertList.crlExtensions) {
+ for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) {
+ if (crl->crl.tbsCertList.crlExtensions->val[j].critical) {
+ hx509_set_error_string(context, 0,
+ HX509_CRL_UNKNOWN_EXTENSION,
+ "Unknown CRL extension");
return HX509_CRL_UNKNOWN_EXTENSION;
+ }
+ }
+ }
if (crl->crl.tbsCertList.revokedCertificates == NULL)
return 0;
@@ -667,7 +815,7 @@ hx509_revoke_verify(hx509_context context,
time_t t;
ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate,
- &c->tbsCertificate.serialNumber);
+ &c->tbsCertificate.serialNumber);
if (ret != 0)
continue;
@@ -680,7 +828,10 @@ hx509_revoke_verify(hx509_context context,
if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical)
return HX509_CRL_UNKNOWN_EXTENSION;
- return HX509_CRL_CERT_REVOKED;
+ hx509_set_error_string(context, 0,
+ HX509_CERT_REVOKED,
+ "Certificate revoked by issuer in CRL");
+ return HX509_CERT_REVOKED;
}
return 0;
@@ -689,6 +840,10 @@ hx509_revoke_verify(hx509_context context,
if (context->flags & HX509_CTX_VERIFY_MISSING_OK)
return 0;
+ hx509_set_error_string(context, HX509_ERROR_APPEND,
+ HX509_REVOKE_STATUS_MISSING,
+ "No revoke status found for "
+ "certificates");
return HX509_REVOKE_STATUS_MISSING;
}
@@ -785,6 +940,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,
@@ -813,41 +984,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;
}
}
@@ -855,12 +1034,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 *
@@ -872,6 +1054,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)
{
@@ -959,10 +1153,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 its not
- * expired. Doesn't verify signature the OCSP reply or its done by a
+/**
+ * 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
@@ -1062,6 +1269,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)
{
@@ -1083,6 +1301,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,
@@ -1091,6 +1321,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)
{
@@ -1098,6 +1341,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)
@@ -1144,6 +1395,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,