diff options
Diffstat (limited to 'crypto/heimdal/lib/hx509/ca.c')
-rw-r--r-- | crypto/heimdal/lib/hx509/ca.c | 1518 |
1 files changed, 0 insertions, 1518 deletions
diff --git a/crypto/heimdal/lib/hx509/ca.c b/crypto/heimdal/lib/hx509/ca.c deleted file mode 100644 index 4026070..0000000 --- a/crypto/heimdal/lib/hx509/ca.c +++ /dev/null @@ -1,1518 +0,0 @@ -/* - * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "hx_locl.h" -#include <pkinit_asn1.h> -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; - SubjectPublicKeyInfo spki; - ExtKeyUsage eku; - GeneralNames san; - unsigned key_usage; - heim_integer serial; - struct { - unsigned int proxy:1; - unsigned int ca:1; - unsigned int key:1; - unsigned int serial:1; - unsigned int domaincontroller:1; - } flags; - time_t notBefore; - time_t notAfter; - int pathLenConstraint; /* both for CA and Proxy */ - 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) -{ - *tbs = calloc(1, sizeof(**tbs)); - if (*tbs == NULL) - return ENOMEM; - - (*tbs)->subject = NULL; - (*tbs)->san.len = 0; - (*tbs)->san.val = NULL; - (*tbs)->eku.len = 0; - (*tbs)->eku.val = NULL; - (*tbs)->pathLenConstraint = 0; - (*tbs)->crldp.len = 0; - (*tbs)->crldp.val = NULL; - - 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) -{ - if (tbs == NULL || *tbs == NULL) - return; - - free_SubjectPublicKeyInfo(&(*tbs)->spki); - free_GeneralNames(&(*tbs)->san); - free_ExtKeyUsage(&(*tbs)->eku); - der_free_heim_integer(&(*tbs)->serial); - free_CRLDistributionPoints(&(*tbs)->crldp); - - hx509_name_free(&(*tbs)->subject); - - memset(*tbs, 0, sizeof(**tbs)); - free(*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, - time_t t) -{ - tbs->notBefore = t; - 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, - time_t t) -{ - tbs->notAfter = t; - 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, - time_t delta) -{ - return hx509_ca_tbs_set_notAfter(context, tbs, time(NULL) + delta); -} - -static const struct units templatebits[] = { - { "ExtendedKeyUsage", HX509_CA_TEMPLATE_EKU }, - { "KeyUsage", HX509_CA_TEMPLATE_KU }, - { "SPKI", HX509_CA_TEMPLATE_SPKI }, - { "notAfter", HX509_CA_TEMPLATE_NOTAFTER }, - { "notBefore", HX509_CA_TEMPLATE_NOTBEFORE }, - { "serial", HX509_CA_TEMPLATE_SERIAL }, - { "subject", HX509_CA_TEMPLATE_SUBJECT }, - { 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, - int flags, - hx509_cert cert) -{ - int ret; - - if (flags & HX509_CA_TEMPLATE_SUBJECT) { - if (tbs->subject) - hx509_name_free(&tbs->subject); - ret = hx509_cert_get_subject(cert, &tbs->subject); - if (ret) { - hx509_set_error_string(context, 0, ret, - "Failed to get subject from template"); - return ret; - } - } - if (flags & HX509_CA_TEMPLATE_SERIAL) { - der_free_heim_integer(&tbs->serial); - ret = hx509_cert_get_serialnumber(cert, &tbs->serial); - tbs->flags.serial = !ret; - if (ret) { - hx509_set_error_string(context, 0, ret, - "Failed to copy serial number"); - return ret; - } - } - if (flags & HX509_CA_TEMPLATE_NOTBEFORE) - tbs->notBefore = hx509_cert_get_notBefore(cert); - if (flags & HX509_CA_TEMPLATE_NOTAFTER) - tbs->notAfter = hx509_cert_get_notAfter(cert); - if (flags & HX509_CA_TEMPLATE_SPKI) { - free_SubjectPublicKeyInfo(&tbs->spki); - ret = hx509_cert_get_SPKI(context, cert, &tbs->spki); - tbs->flags.key = !ret; - if (ret) - return ret; - } - if (flags & HX509_CA_TEMPLATE_KU) { - KeyUsage ku; - ret = _hx509_cert_get_keyusage(context, cert, &ku); - if (ret) - return ret; - tbs->key_usage = KeyUsage2int(ku); - } - if (flags & HX509_CA_TEMPLATE_EKU) { - ExtKeyUsage eku; - int i; - ret = _hx509_cert_get_eku(context, cert, &eku); - if (ret) - return ret; - for (i = 0; i < eku.len; i++) { - ret = hx509_ca_tbs_add_eku(context, tbs, &eku.val[i]); - if (ret) { - free_ExtKeyUsage(&eku); - return ret; - } - } - free_ExtKeyUsage(&eku); - } - 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, - int pathLenConstraint) -{ - tbs->flags.ca = 1; - tbs->pathLenConstraint = pathLenConstraint; - 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, - int pathLenConstraint) -{ - tbs->flags.proxy = 1; - tbs->pathLenConstraint = pathLenConstraint; - return 0; -} - - -/** - * 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) -{ - tbs->flags.domaincontroller = 1; - 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, - const SubjectPublicKeyInfo *spki) -{ - int ret; - free_SubjectPublicKeyInfo(&tbs->spki); - ret = copy_SubjectPublicKeyInfo(spki, &tbs->spki); - tbs->flags.key = !ret; - 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, - const heim_integer *serialNumber) -{ - int ret; - der_free_heim_integer(&tbs->serial); - ret = der_copy_heim_integer(serialNumber, &tbs->serial); - tbs->flags.serial = !ret; - 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, - const heim_oid *oid) -{ - void *ptr; - int ret; - unsigned i; - - /* search for duplicates */ - for (i = 0; i < tbs->eku.len; i++) { - if (der_heim_oid_cmp(oid, &tbs->eku.val[i]) == 0) - return 0; - } - - ptr = realloc(tbs->eku.val, sizeof(tbs->eku.val[0]) * (tbs->eku.len + 1)); - if (ptr == NULL) { - hx509_set_error_string(context, 0, ENOMEM, "out of memory"); - return ENOMEM; - } - tbs->eku.val = ptr; - ret = der_copy_oid(oid, &tbs->eku.val[tbs->eku.len]); - if (ret) { - hx509_set_error_string(context, 0, ret, "out of memory"); - return ret; - } - tbs->eku.len += 1; - 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, - const char *uri, - hx509_name issuername) -{ - DistributionPoint dp; - int ret; - - memset(&dp, 0, sizeof(dp)); - - dp.distributionPoint = ecalloc(1, sizeof(*dp.distributionPoint)); - - { - DistributionPointName name; - GeneralName gn; - size_t size; - - name.element = choice_DistributionPointName_fullName; - name.u.fullName.len = 1; - name.u.fullName.val = &gn; - - gn.element = choice_GeneralName_uniformResourceIdentifier; - gn.u.uniformResourceIdentifier = rk_UNCONST(uri); - - ASN1_MALLOC_ENCODE(DistributionPointName, - dp.distributionPoint->data, - dp.distributionPoint->length, - &name, &size, ret); - if (ret) { - hx509_set_error_string(context, 0, ret, - "Failed to encoded DistributionPointName"); - goto out; - } - if (dp.distributionPoint->length != size) - _hx509_abort("internal ASN.1 encoder error"); - } - - if (issuername) { -#if 1 - /** - * issuername not supported - */ - hx509_set_error_string(context, 0, EINVAL, - "CRLDistributionPoints.name.issuername not yet supported"); - return EINVAL; -#else - GeneralNames *crlissuer; - GeneralName gn; - Name n; - - crlissuer = calloc(1, sizeof(*crlissuer)); - if (crlissuer == NULL) { - return ENOMEM; - } - memset(&gn, 0, sizeof(gn)); - - gn.element = choice_GeneralName_directoryName; - ret = hx509_name_to_Name(issuername, &n); - if (ret) { - hx509_set_error_string(context, 0, ret, "out of memory"); - goto out; - } - - gn.u.directoryName.element = n.element; - gn.u.directoryName.u.rdnSequence = n.u.rdnSequence; - - ret = add_GeneralNames(&crlissuer, &gn); - free_Name(&n); - if (ret) { - hx509_set_error_string(context, 0, ret, "out of memory"); - goto out; - } - - dp.cRLIssuer = &crlissuer; -#endif - } - - ret = add_CRLDistributionPoints(&tbs->crldp, &dp); - if (ret) { - hx509_set_error_string(context, 0, ret, "out of memory"); - goto out; - } - -out: - free_DistributionPoint(&dp); - - 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, - const heim_oid *oid, - const heim_octet_string *os) -{ - GeneralName gn; - - memset(&gn, 0, sizeof(gn)); - gn.element = choice_GeneralName_otherName; - gn.u.otherName.type_id = *oid; - gn.u.otherName.value = *os; - - 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, - hx509_ca_tbs tbs, - const char *principal) -{ - heim_octet_string os; - KRB5PrincipalName p; - size_t size; - int ret; - char *s = NULL; - - memset(&p, 0, sizeof(p)); - - /* parse principal */ - { - const char *str; - char *q; - int n; - - /* count number of component */ - n = 1; - for(str = principal; *str != '\0' && *str != '@'; str++){ - if(*str=='\\'){ - if(str[1] == '\0' || str[1] == '@') { - ret = HX509_PARSING_NAME_FAILED; - hx509_set_error_string(context, 0, ret, - "trailing \\ in principal name"); - goto out; - } - str++; - } else if(*str == '/') - n++; - } - p.principalName.name_string.val = - calloc(n, sizeof(*p.principalName.name_string.val)); - if (p.principalName.name_string.val == NULL) { - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "malloc: out of memory"); - goto out; - } - p.principalName.name_string.len = n; - - p.principalName.name_type = KRB5_NT_PRINCIPAL; - q = s = strdup(principal); - if (q == NULL) { - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "malloc: out of memory"); - goto out; - } - p.realm = strrchr(q, '@'); - if (p.realm == NULL) { - ret = HX509_PARSING_NAME_FAILED; - hx509_set_error_string(context, 0, ret, "Missing @ in principal"); - goto out; - }; - *p.realm++ = '\0'; - - n = 0; - while (q) { - p.principalName.name_string.val[n++] = q; - q = strchr(q, '/'); - if (q) - *q++ = '\0'; - } - } - - ASN1_MALLOC_ENCODE(KRB5PrincipalName, os.data, os.length, &p, &size, ret); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - if (size != os.length) - _hx509_abort("internal ASN.1 encoder error"); - - ret = hx509_ca_tbs_add_san_otherName(context, - tbs, - oid_id_pkinit_san(), - &os); - free(os.data); -out: - if (p.principalName.name_string.val) - free (p.principalName.name_string.val); - if (s) - free(s); - return ret; -} - -/* - * - */ - -static int -add_utf8_san(hx509_context context, - hx509_ca_tbs tbs, - const heim_oid *oid, - const char *string) -{ - const PKIXXmppAddr ustring = (const PKIXXmppAddr)string; - heim_octet_string os; - size_t size; - int ret; - - os.length = 0; - os.data = NULL; - - ASN1_MALLOC_ENCODE(PKIXXmppAddr, os.data, os.length, &ustring, &size, ret); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - if (size != os.length) - _hx509_abort("internal ASN.1 encoder error"); - - ret = hx509_ca_tbs_add_san_otherName(context, - tbs, - oid, - &os); - free(os.data); -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, - const char *principal) -{ - 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, - const char *jid) -{ - return add_utf8_san(context, tbs, oid_id_pkix_on_xmppAddr(), jid); -} - - -/** - * 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, - const char *dnsname) -{ - GeneralName gn; - - memset(&gn, 0, sizeof(gn)); - gn.element = choice_GeneralName_dNSName; - gn.u.dNSName = rk_UNCONST(dnsname); - - 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, - const char *rfc822Name) -{ - GeneralName gn; - - memset(&gn, 0, sizeof(gn)); - gn.element = choice_GeneralName_rfc822Name; - gn.u.rfc822Name = rk_UNCONST(rfc822Name); - - 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, - hx509_ca_tbs tbs, - hx509_name subject) -{ - if (tbs->subject) - hx509_name_free(&tbs->subject); - 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, - hx509_env env) -{ - return hx509_name_expand(context, tbs->subject, env); -} - -static int -add_extension(hx509_context context, - TBSCertificate *tbsc, - int critical_flag, - const heim_oid *oid, - const heim_octet_string *data) -{ - Extension ext; - int ret; - - memset(&ext, 0, sizeof(ext)); - - if (critical_flag) { - ext.critical = malloc(sizeof(*ext.critical)); - if (ext.critical == NULL) { - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - *ext.critical = TRUE; - } - - ret = der_copy_oid(oid, &ext.extnID); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - ret = der_copy_octet_string(data, &ext.extnValue); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - ret = add_Extensions(tbsc->extensions, &ext); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } -out: - free_Extension(&ext); - return ret; -} - -static int -build_proxy_prefix(hx509_context context, const Name *issuer, Name *subject) -{ - char *tstr; - time_t t; - int ret; - - ret = copy_Name(issuer, subject); - if (ret) { - hx509_set_error_string(context, 0, ret, - "Failed to copy subject name"); - return ret; - } - - t = time(NULL); - asprintf(&tstr, "ts-%lu", (unsigned long)t); - if (tstr == NULL) { - hx509_set_error_string(context, 0, ENOMEM, - "Failed to copy subject name"); - return ENOMEM; - } - /* prefix with CN=<ts>,...*/ - ret = _hx509_name_modify(context, subject, 1, oid_id_at_commonName(), tstr); - free(tstr); - if (ret) - free_Name(subject); - return ret; -} - -static int -ca_sign(hx509_context context, - hx509_ca_tbs tbs, - hx509_private_key signer, - const AuthorityKeyIdentifier *ai, - const Name *issuername, - hx509_cert *certificate) -{ - heim_octet_string data; - Certificate c; - TBSCertificate *tbsc; - size_t size; - int ret; - const AlgorithmIdentifier *sigalg; - time_t notBefore; - time_t notAfter; - unsigned key_usage; - - sigalg = _hx509_crypto_default_sig_alg; - - memset(&c, 0, sizeof(c)); - - /* - * Default values are: Valid since 24h ago, valid one year into - * the future, KeyUsage digitalSignature and keyEncipherment set, - * and keyCertSign for CA certificates. - */ - notBefore = tbs->notBefore; - if (notBefore == 0) - notBefore = time(NULL) - 3600 * 24; - notAfter = tbs->notAfter; - if (notAfter == 0) - notAfter = time(NULL) + 3600 * 24 * 365; - - key_usage = tbs->key_usage; - if (key_usage == 0) { - KeyUsage ku; - memset(&ku, 0, sizeof(ku)); - ku.digitalSignature = 1; - ku.keyEncipherment = 1; - key_usage = KeyUsage2int(ku); - } - - if (tbs->flags.ca) { - KeyUsage ku; - memset(&ku, 0, sizeof(ku)); - ku.keyCertSign = 1; - ku.cRLSign = 1; - key_usage |= KeyUsage2int(ku); - } - - /* - * - */ - - tbsc = &c.tbsCertificate; - - if (tbs->flags.key == 0) { - ret = EINVAL; - hx509_set_error_string(context, 0, ret, "No public key set"); - return ret; - } - /* - * Don't put restrictions on proxy certificate's subject name, it - * will be generated below. - */ - if (!tbs->flags.proxy) { - if (tbs->subject == NULL) { - hx509_set_error_string(context, 0, EINVAL, "No subject name set"); - return EINVAL; - } - if (hx509_name_is_null_p(tbs->subject) && tbs->san.len == 0) { - hx509_set_error_string(context, 0, EINVAL, - "NULL subject and no SubjectAltNames"); - return EINVAL; - } - } - if (tbs->flags.ca && tbs->flags.proxy) { - hx509_set_error_string(context, 0, EINVAL, "Can't be proxy and CA " - "at the same time"); - return EINVAL; - } - if (tbs->flags.proxy) { - if (tbs->san.len > 0) { - hx509_set_error_string(context, 0, EINVAL, - "Proxy certificate is not allowed " - "to have SubjectAltNames"); - return EINVAL; - } - } - - /* version [0] Version OPTIONAL, -- EXPLICIT nnn DEFAULT 1, */ - tbsc->version = calloc(1, sizeof(*tbsc->version)); - if (tbsc->version == NULL) { - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - *tbsc->version = rfc3280_version_3; - /* serialNumber CertificateSerialNumber, */ - if (tbs->flags.serial) { - ret = der_copy_heim_integer(&tbs->serial, &tbsc->serialNumber); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - } else { - tbsc->serialNumber.length = 20; - tbsc->serialNumber.data = malloc(tbsc->serialNumber.length); - if (tbsc->serialNumber.data == NULL){ - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - /* XXX diffrent */ - RAND_bytes(tbsc->serialNumber.data, tbsc->serialNumber.length); - ((unsigned char *)tbsc->serialNumber.data)[0] &= 0x7f; - } - /* signature AlgorithmIdentifier, */ - ret = copy_AlgorithmIdentifier(sigalg, &tbsc->signature); - if (ret) { - hx509_set_error_string(context, 0, ret, "Failed to copy sigature alg"); - goto out; - } - /* issuer Name, */ - if (issuername) - ret = copy_Name(issuername, &tbsc->issuer); - else - ret = hx509_name_to_Name(tbs->subject, &tbsc->issuer); - if (ret) { - hx509_set_error_string(context, 0, ret, "Failed to copy issuer name"); - goto out; - } - /* validity Validity, */ - tbsc->validity.notBefore.element = choice_Time_generalTime; - tbsc->validity.notBefore.u.generalTime = notBefore; - tbsc->validity.notAfter.element = choice_Time_generalTime; - tbsc->validity.notAfter.u.generalTime = notAfter; - /* subject Name, */ - if (tbs->flags.proxy) { - ret = build_proxy_prefix(context, &tbsc->issuer, &tbsc->subject); - if (ret) - goto out; - } else { - ret = hx509_name_to_Name(tbs->subject, &tbsc->subject); - if (ret) { - hx509_set_error_string(context, 0, ret, - "Failed to copy subject name"); - goto out; - } - } - /* subjectPublicKeyInfo SubjectPublicKeyInfo, */ - ret = copy_SubjectPublicKeyInfo(&tbs->spki, &tbsc->subjectPublicKeyInfo); - if (ret) { - hx509_set_error_string(context, 0, ret, "Failed to copy spki"); - goto out; - } - /* issuerUniqueID [1] IMPLICIT BIT STRING OPTIONAL */ - /* subjectUniqueID [2] IMPLICIT BIT STRING OPTIONAL */ - /* extensions [3] EXPLICIT Extensions OPTIONAL */ - tbsc->extensions = calloc(1, sizeof(*tbsc->extensions)); - if (tbsc->extensions == NULL) { - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - - /* Add the text BMP string Domaincontroller to the cert */ - if (tbs->flags.domaincontroller) { - data.data = rk_UNCONST("\x1e\x20\x00\x44\x00\x6f\x00\x6d" - "\x00\x61\x00\x69\x00\x6e\x00\x43" - "\x00\x6f\x00\x6e\x00\x74\x00\x72" - "\x00\x6f\x00\x6c\x00\x6c\x00\x65" - "\x00\x72"); - data.length = 34; - - ret = add_extension(context, tbsc, 0, - oid_id_ms_cert_enroll_domaincontroller(), - &data); - if (ret) - goto out; - } - - /* add KeyUsage */ - { - KeyUsage ku; - - ku = int2KeyUsage(key_usage); - ASN1_MALLOC_ENCODE(KeyUsage, data.data, data.length, &ku, &size, ret); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - if (size != data.length) - _hx509_abort("internal ASN.1 encoder error"); - ret = add_extension(context, tbsc, 1, - oid_id_x509_ce_keyUsage(), &data); - free(data.data); - if (ret) - goto out; - } - - /* add ExtendedKeyUsage */ - if (tbs->eku.len > 0) { - ASN1_MALLOC_ENCODE(ExtKeyUsage, data.data, data.length, - &tbs->eku, &size, ret); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - if (size != data.length) - _hx509_abort("internal ASN.1 encoder error"); - ret = add_extension(context, tbsc, 0, - oid_id_x509_ce_extKeyUsage(), &data); - free(data.data); - if (ret) - goto out; - } - - /* add Subject Alternative Name */ - if (tbs->san.len > 0) { - ASN1_MALLOC_ENCODE(GeneralNames, data.data, data.length, - &tbs->san, &size, ret); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - if (size != data.length) - _hx509_abort("internal ASN.1 encoder error"); - ret = add_extension(context, tbsc, 0, - oid_id_x509_ce_subjectAltName(), - &data); - free(data.data); - if (ret) - goto out; - } - - /* Add Authority Key Identifier */ - if (ai) { - ASN1_MALLOC_ENCODE(AuthorityKeyIdentifier, data.data, data.length, - ai, &size, ret); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - if (size != data.length) - _hx509_abort("internal ASN.1 encoder error"); - ret = add_extension(context, tbsc, 0, - oid_id_x509_ce_authorityKeyIdentifier(), - &data); - free(data.data); - if (ret) - goto out; - } - - /* Add Subject Key Identifier */ - { - SubjectKeyIdentifier si; - unsigned char hash[SHA_DIGEST_LENGTH]; - - { - SHA_CTX m; - - SHA1_Init(&m); - SHA1_Update(&m, tbs->spki.subjectPublicKey.data, - tbs->spki.subjectPublicKey.length / 8); - SHA1_Final (hash, &m); - } - - si.data = hash; - si.length = sizeof(hash); - - ASN1_MALLOC_ENCODE(SubjectKeyIdentifier, data.data, data.length, - &si, &size, ret); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - if (size != data.length) - _hx509_abort("internal ASN.1 encoder error"); - ret = add_extension(context, tbsc, 0, - oid_id_x509_ce_subjectKeyIdentifier(), - &data); - free(data.data); - if (ret) - goto out; - } - - /* Add BasicConstraints */ - { - BasicConstraints bc; - int aCA = 1; - uint32_t path; - - memset(&bc, 0, sizeof(bc)); - - if (tbs->flags.ca) { - bc.cA = &aCA; - if (tbs->pathLenConstraint >= 0) { - path = tbs->pathLenConstraint; - bc.pathLenConstraint = &path; - } - } - - ASN1_MALLOC_ENCODE(BasicConstraints, data.data, data.length, - &bc, &size, ret); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - if (size != data.length) - _hx509_abort("internal ASN.1 encoder error"); - /* Critical if this is a CA */ - ret = add_extension(context, tbsc, tbs->flags.ca, - oid_id_x509_ce_basicConstraints(), - &data); - free(data.data); - if (ret) - goto out; - } - - /* add Proxy */ - if (tbs->flags.proxy) { - ProxyCertInfo info; - - memset(&info, 0, sizeof(info)); - - if (tbs->pathLenConstraint >= 0) { - info.pCPathLenConstraint = - malloc(sizeof(*info.pCPathLenConstraint)); - if (info.pCPathLenConstraint == NULL) { - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - *info.pCPathLenConstraint = tbs->pathLenConstraint; - } - - ret = der_copy_oid(oid_id_pkix_ppl_inheritAll(), - &info.proxyPolicy.policyLanguage); - if (ret) { - free_ProxyCertInfo(&info); - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - - ASN1_MALLOC_ENCODE(ProxyCertInfo, data.data, data.length, - &info, &size, ret); - free_ProxyCertInfo(&info); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - if (size != data.length) - _hx509_abort("internal ASN.1 encoder error"); - ret = add_extension(context, tbsc, 0, - oid_id_pkix_pe_proxyCertInfo(), - &data); - free(data.data); - if (ret) - goto out; - } - - if (tbs->crldp.len) { - - ASN1_MALLOC_ENCODE(CRLDistributionPoints, data.data, data.length, - &tbs->crldp, &size, ret); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - if (size != data.length) - _hx509_abort("internal ASN.1 encoder error"); - ret = add_extension(context, tbsc, FALSE, - oid_id_x509_ce_cRLDistributionPoints(), - &data); - free(data.data); - if (ret) - goto out; - } - - ASN1_MALLOC_ENCODE(TBSCertificate, data.data, data.length,tbsc, &size, ret); - if (ret) { - hx509_set_error_string(context, 0, ret, "malloc out of memory"); - goto out; - } - if (data.length != size) - _hx509_abort("internal ASN.1 encoder error"); - - ret = _hx509_create_signature_bitstring(context, - signer, - sigalg, - &data, - &c.signatureAlgorithm, - &c.signatureValue); - free(data.data); - if (ret) - goto out; - - ret = hx509_cert_init(context, &c, certificate); - if (ret) - goto out; - - free_Certificate(&c); - - return 0; - -out: - free_Certificate(&c); - return ret; -} - -static int -get_AuthorityKeyIdentifier(hx509_context context, - const Certificate *certificate, - AuthorityKeyIdentifier *ai) -{ - SubjectKeyIdentifier si; - int ret; - - ret = _hx509_find_extension_subject_key_id(certificate, &si); - if (ret == 0) { - ai->keyIdentifier = calloc(1, sizeof(*ai->keyIdentifier)); - if (ai->keyIdentifier == NULL) { - free_SubjectKeyIdentifier(&si); - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - ret = der_copy_octet_string(&si, ai->keyIdentifier); - free_SubjectKeyIdentifier(&si); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - } else { - GeneralNames gns; - GeneralName gn; - Name name; - - memset(&gn, 0, sizeof(gn)); - memset(&gns, 0, sizeof(gns)); - memset(&name, 0, sizeof(name)); - - ai->authorityCertIssuer = - calloc(1, sizeof(*ai->authorityCertIssuer)); - if (ai->authorityCertIssuer == NULL) { - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - ai->authorityCertSerialNumber = - calloc(1, sizeof(*ai->authorityCertSerialNumber)); - if (ai->authorityCertSerialNumber == NULL) { - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - - /* - * XXX unbreak when asn1 compiler handle IMPLICIT - * - * This is so horrible. - */ - - ret = copy_Name(&certificate->tbsCertificate.subject, &name); - if (ai->authorityCertSerialNumber == NULL) { - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - - memset(&gn, 0, sizeof(gn)); - gn.element = choice_GeneralName_directoryName; - gn.u.directoryName.element = - choice_GeneralName_directoryName_rdnSequence; - gn.u.directoryName.u.rdnSequence = name.u.rdnSequence; - - ret = add_GeneralNames(&gns, &gn); - if (ret) { - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - - ai->authorityCertIssuer->val = gns.val; - ai->authorityCertIssuer->len = gns.len; - - ret = der_copy_heim_integer(&certificate->tbsCertificate.serialNumber, - ai->authorityCertSerialNumber); - if (ai->authorityCertSerialNumber == NULL) { - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - } -out: - if (ret) - free_AuthorityKeyIdentifier(ai); - return ret; -} - - -/** - * 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, - hx509_cert signer, - hx509_cert *certificate) -{ - const Certificate *signer_cert; - AuthorityKeyIdentifier ai; - int ret; - - memset(&ai, 0, sizeof(ai)); - - signer_cert = _hx509_get_cert(signer); - - ret = get_AuthorityKeyIdentifier(context, signer_cert, &ai); - if (ret) - goto out; - - ret = ca_sign(context, - tbs, - _hx509_cert_private_key(signer), - &ai, - &signer_cert->tbsCertificate.subject, - certificate); - -out: - free_AuthorityKeyIdentifier(&ai); - - 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, - hx509_private_key signer, - hx509_cert *certificate) -{ - return ca_sign(context, - tbs, - signer, - NULL, - NULL, - certificate); -} |