diff options
Diffstat (limited to 'source4/heimdal/lib/hx509/ca.c')
-rw-r--r-- | source4/heimdal/lib/hx509/ca.c | 893 |
1 files changed, 893 insertions, 0 deletions
diff --git a/source4/heimdal/lib/hx509/ca.c b/source4/heimdal/lib/hx509/ca.c new file mode 100644 index 0000000000..1a5b4947be --- /dev/null +++ b/source4/heimdal/lib/hx509/ca.c @@ -0,0 +1,893 @@ +/* + * Copyright (c) 2006 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,v 1.12 2007/01/05 18:40:46 lha Exp $"); + +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; + } flags; + time_t notBefore; + time_t notAfter; + int pathLenConstraint; /* both for CA and Proxy */ +}; + +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; + + return 0; +} + +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); + + hx509_name_free(&(*tbs)->subject); + + memset(*tbs, 0, sizeof(**tbs)); + free(*tbs); + *tbs = NULL; +} + +int +hx509_ca_tbs_set_notBefore(hx509_context context, + hx509_ca_tbs tbs, + time_t t) +{ + tbs->notBefore = t; + return 0; +} + +int +hx509_ca_tbs_set_notAfter(hx509_context context, + hx509_ca_tbs tbs, + time_t t) +{ + tbs->notAfter = t; + return 0; +} + +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); +} + +int +hx509_ca_tbs_set_ca(hx509_context context, + hx509_ca_tbs tbs, + int pathLenConstraint) +{ + tbs->flags.ca = 1; + tbs->pathLenConstraint = pathLenConstraint; + return 0; +} + +int +hx509_ca_tbs_set_proxy(hx509_context context, + hx509_ca_tbs tbs, + int pathLenConstraint) +{ + tbs->flags.proxy = 1; + tbs->pathLenConstraint = pathLenConstraint; + return 0; +} + + +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; +} + +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; +} + +int +hx509_ca_tbs_add_eku(hx509_context contex, + hx509_ca_tbs tbs, + const heim_oid *oid) +{ + void *ptr; + int ret; + + ptr = realloc(tbs->eku.val, sizeof(tbs->eku.val[0]) * (tbs->eku.len + 1)); + if (ptr == NULL) + return ENOMEM; + tbs->eku.val = ptr; + ret = der_copy_oid(oid, &tbs->eku.val[tbs->eku.len]); + if (ret) + return ret; + tbs->eku.len += 1; + return 0; +} + +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); +} + + +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; +} + +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); +} + +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); +} + + +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); +} + +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_signature_rsa_with_sha1(); + + 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; + 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; + } + if (tbs->subject == NULL && !tbs->flags.proxy) { + ret = EINVAL; + hx509_set_error_string(context, 0, ret, "No subject name set"); + return ret; + } + if (tbs->flags.ca && tbs->flags.proxy) { + ret = EINVAL; + hx509_set_error_string(context, 0, ret, "Can't be proxy and CA " + "at the same time"); + return ret; + } + 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 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"); + ret = add_extension(context, tbsc, 0, + 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_pe_proxyCertInfo(), + &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) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + ret = der_copy_octet_string(&si, ai->keyIdentifier); + 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; + } + + 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; +} + + +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; +} + +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); +} |