From 561ee23f218c7a68a2ef46525502f978e56fc1bb Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Tue, 29 Nov 2016 13:30:55 +0100 Subject: MOVED TO: https://github.com/p11-glue/p11-kit This repository has moved to GitHub to allow further contributions and more flexibility who can merge changes. More details here: https://lists.freedesktop.org/archives/p11-glue/2016-November/000626.html --- trust/builder.c | 1872 ------------------------------------------------------- 1 file changed, 1872 deletions(-) delete mode 100644 trust/builder.c (limited to 'trust/builder.c') diff --git a/trust/builder.c b/trust/builder.c deleted file mode 100644 index e0ce370..0000000 --- a/trust/builder.c +++ /dev/null @@ -1,1872 +0,0 @@ -/* - * Copyright (C) 2012 Red Hat Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * * 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. - * * The names of contributors to this software may not be - * used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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. - * - * Author: Stef Walter - */ - -#include "config.h" - -#define P11_DEBUG_FLAG P11_DEBUG_TRUST - -#include "array.h" -#include "asn1.h" -#include "attrs.h" -#include "builder.h" -#include "constants.h" -#include "debug.h" -#include "digest.h" -#include "index.h" -#include "message.h" -#include "oid.h" -#include "pkcs11i.h" -#include "pkcs11x.h" -#include "utf8.h" -#include "x509.h" - -#include -#include -#include - -struct _p11_builder { - p11_asn1_cache *asn1_cache; - p11_dict *asn1_defs; - int flags; -}; - -enum { - NONE = 0, - CREATE = 1 << 0, - MODIFY = 1 << 1, - REQUIRE = 1 << 2, - WANT = 1 << 3, -}; - -enum { - NORMAL_BUILD = 0, - GENERATED_CLASS = 1 << 0, -}; - -typedef struct { - int build_flags; - struct { - CK_ATTRIBUTE_TYPE type; - int flags; - bool (*validate) (p11_builder *, CK_ATTRIBUTE *); - } attrs[32]; - CK_ATTRIBUTE * (*populate) (p11_builder *, p11_index *, CK_ATTRIBUTE *); - CK_RV (*validate) (p11_builder *, CK_ATTRIBUTE *, CK_ATTRIBUTE *); -} builder_schema; - -static node_asn * -decode_or_get_asn1 (p11_builder *builder, - const char *struct_name, - const unsigned char *der, - size_t length) -{ - node_asn *node; - - node = p11_asn1_cache_get (builder->asn1_cache, struct_name, der, length); - if (node != NULL) - return node; - - node = p11_asn1_decode (builder->asn1_defs, struct_name, der, length, NULL); - if (node != NULL) - p11_asn1_cache_take (builder->asn1_cache, node, struct_name, der, length); - - return node; -} - -static unsigned char * -lookup_extension (p11_builder *builder, - p11_index *index, - CK_ATTRIBUTE *cert, - CK_ATTRIBUTE *public_key, - const unsigned char *oid, - size_t *ext_len) -{ - CK_OBJECT_CLASS klass = CKO_X_CERTIFICATE_EXTENSION; - CK_OBJECT_HANDLE obj; - CK_ATTRIBUTE *attrs; - CK_ATTRIBUTE *label; - void *value; - size_t length; - node_asn *node; - - CK_ATTRIBUTE match[] = { - { CKA_PUBLIC_KEY_INFO, }, - { CKA_OBJECT_ID, (void *)oid, p11_oid_length (oid) }, - { CKA_CLASS, &klass, sizeof (klass) }, - { CKA_INVALID }, - }; - - if (public_key == NULL || public_key->type == CKA_INVALID) - public_key = p11_attrs_find_valid (cert, CKA_PUBLIC_KEY_INFO); - - /* Look for an attached certificate extension */ - if (public_key != NULL) { - memcpy (match, public_key, sizeof (CK_ATTRIBUTE)); - obj = p11_index_find (index, match, -1); - attrs = p11_index_lookup (index, obj); - if (attrs != NULL) { - value = p11_attrs_find_value (attrs, CKA_VALUE, &length); - if (value != NULL) { - node = decode_or_get_asn1 (builder, "PKIX1.Extension", value, length); - if (node == NULL) { - label = p11_attrs_find_valid (attrs, CKA_LABEL); - if (label == NULL) - label = p11_attrs_find_valid (cert, CKA_LABEL); - p11_message ("%.*s: invalid certificate extension", - label ? (int)label->ulValueLen : 7, - label ? (char *)label->pValue : "unknown"); - return NULL; - } - return p11_asn1_read (node, "extnValue", ext_len); - } - } - } - - /* Couldn't find a parsed extension, so look in the current certificate */ - value = p11_attrs_find_value (cert, CKA_VALUE, &length); - if (value != NULL) { - node = decode_or_get_asn1 (builder, "PKIX1.Certificate", value, length); - return_val_if_fail (node != NULL, NULL); - return p11_x509_find_extension (node, oid, value, length, ext_len); - } - - return NULL; -} - -static CK_OBJECT_HANDLE * -lookup_related (p11_index *index, - CK_OBJECT_CLASS klass, - CK_ATTRIBUTE *attr) -{ - CK_ATTRIBUTE match[] = { - { attr->type, attr->pValue, attr->ulValueLen }, - { CKA_CLASS, &klass, sizeof (klass) }, - { CKA_INVALID } - }; - - return p11_index_find_all (index, match, -1); -} - -p11_builder * -p11_builder_new (int flags) -{ - p11_builder *builder; - - builder = calloc (1, sizeof (p11_builder)); - return_val_if_fail (builder != NULL, NULL); - - builder->asn1_cache = p11_asn1_cache_new (); - return_val_if_fail (builder->asn1_cache, NULL); - builder->asn1_defs = p11_asn1_cache_defs (builder->asn1_cache); - - builder->flags = flags; - return builder; -} - -static int -atoin (const char *p, - int digits) -{ - int ret = 0, base = 1; - while(--digits >= 0) { - if (p[digits] < '0' || p[digits] > '9') - return -1; - ret += (p[digits] - '0') * base; - base *= 10; - } - return ret; -} - -static bool -type_bool (p11_builder *builder, - CK_ATTRIBUTE *attr) -{ - return (attr->pValue != NULL && - sizeof (CK_BBOOL) == attr->ulValueLen); -} - -static bool -type_ulong (p11_builder *builder, - CK_ATTRIBUTE *attr) -{ - return (attr->pValue != NULL && - sizeof (CK_ULONG) == attr->ulValueLen); -} - -static bool -type_utf8 (p11_builder *builder, - CK_ATTRIBUTE *attr) -{ - if (attr->ulValueLen == 0) - return true; - if (attr->pValue == NULL) - return false; - return p11_utf8_validate (attr->pValue, attr->ulValueLen); -} - -static bool -type_date (p11_builder *builder, - CK_ATTRIBUTE *attr) -{ - CK_DATE *date; - struct tm tm; - struct tm two; - - if (attr->ulValueLen == 0) - return true; - if (attr->pValue == NULL || attr->ulValueLen != sizeof (CK_DATE)) - return false; - - date = attr->pValue; - memset (&tm, 0, sizeof (tm)); - tm.tm_year = atoin ((char *)date->year, 4) - 1900; - tm.tm_mon = atoin ((char *)date->month, 2); - tm.tm_mday = atoin ((char *)date->day, 2); - - if (tm.tm_year < 0 || tm.tm_mon <= 0 || tm.tm_mday <= 0) - return false; - - memcpy (&two, &tm, sizeof (tm)); - if (mktime (&two) < 0) - return false; - - /* If mktime changed anything, then bad date */ - if (tm.tm_year != two.tm_year || - tm.tm_mon != two.tm_mon || - tm.tm_mday != two.tm_mday) - return false; - - return true; -} - -static bool -check_der_struct (p11_builder *builder, - const char *struct_name, - CK_ATTRIBUTE *attr) -{ - node_asn *asn; - - if (attr->ulValueLen == 0) - return true; - if (attr->pValue == NULL) - return false; - - asn = p11_asn1_decode (builder->asn1_defs, struct_name, - attr->pValue, attr->ulValueLen, NULL); - - if (asn == NULL) - return false; - - asn1_delete_structure (&asn); - return true; -} - -static bool -type_der_name (p11_builder *builder, - CK_ATTRIBUTE *attr) -{ - return check_der_struct (builder, "PKIX1.Name", attr); -} - -static bool -type_der_serial (p11_builder *builder, - CK_ATTRIBUTE *attr) -{ - return check_der_struct (builder, "PKIX1.CertificateSerialNumber", attr); -} - -static bool -type_der_oid (p11_builder *builder, - CK_ATTRIBUTE *attr) -{ - /* AttributeType is an OBJECT ID */ - return check_der_struct (builder, "PKIX1.AttributeType", attr); -} - -static bool -type_der_cert (p11_builder *builder, - CK_ATTRIBUTE *attr) -{ - return check_der_struct (builder, "PKIX1.Certificate", attr); -} - -static bool -type_der_key (p11_builder *builder, - CK_ATTRIBUTE *attr) -{ - return check_der_struct (builder, "PKIX1.SubjectPublicKeyInfo", attr); -} - -static bool -type_der_ext (p11_builder *builder, - CK_ATTRIBUTE *attr) -{ - return check_der_struct (builder, "PKIX1.Extension", attr); -} - -#define COMMON_ATTRS \ - { CKA_CLASS, REQUIRE | CREATE, type_ulong }, \ - { CKA_TOKEN, CREATE | WANT, type_bool }, \ - { CKA_MODIFIABLE, CREATE | WANT, type_bool }, \ - { CKA_PRIVATE, CREATE, type_bool }, \ - { CKA_LABEL, CREATE | MODIFY | WANT, type_utf8 }, \ - { CKA_X_GENERATED, CREATE }, \ - { CKA_X_ORIGIN, NONE } \ - -static CK_ATTRIBUTE * -common_populate (p11_builder *builder, - p11_index *index, - CK_ATTRIBUTE *unused) -{ - CK_BBOOL tokenv = CK_FALSE; - CK_BBOOL modifiablev = CK_TRUE; - CK_BBOOL privatev = CK_FALSE; - CK_BBOOL generatedv = CK_FALSE; - - CK_ATTRIBUTE token = { CKA_TOKEN, &tokenv, sizeof (tokenv), }; - CK_ATTRIBUTE privat = { CKA_PRIVATE, &privatev, sizeof (privatev) }; - CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &modifiablev, sizeof (modifiablev) }; - CK_ATTRIBUTE generated = { CKA_X_GENERATED, &generatedv, sizeof (generatedv) }; - CK_ATTRIBUTE label = { CKA_LABEL, "", 0 }; - - if (builder->flags & P11_BUILDER_FLAG_TOKEN) { - tokenv = CK_TRUE; - modifiablev = CK_FALSE; - } - - return p11_attrs_build (NULL, &token, &privat, &modifiable, &label, &generated, NULL); -} - -static void -calc_check_value (const unsigned char *data, - size_t length, - CK_BYTE *check_value) -{ - unsigned char checksum[P11_DIGEST_SHA1_LEN]; - p11_digest_sha1 (checksum, data, length, NULL); - memcpy (check_value, checksum, 3); -} - -static int -century_for_two_digit_year (int year) -{ - time_t now; - struct tm tm; - int century, current; - - return_val_if_fail (year >= 0 && year <= 99, -1); - - /* Get the current year */ - now = time (NULL); - return_val_if_fail (now >= 0, -1); - if (!gmtime_r (&now, &tm)) - return_val_if_reached (-1); - - current = (tm.tm_year % 100); - century = (tm.tm_year + 1900) - current; - - /* - * Check if it's within 40 years before the - * current date. - */ - if (current < 40) { - if (year < current) - return century; - if (year > 100 - (40 - current)) - return century - 100; - } else { - if (year < current && year > (current - 40)) - return century; - } - - /* - * If it's after then adjust for overflows to - * the next century. - */ - if (year < current) - return century + 100; - else - return century; -} - -static bool -calc_date (node_asn *node, - const char *field, - CK_DATE *date) -{ - node_asn *choice; - char buf[64]; - int century; - char *sub; - int year; - int len; - int ret; - - if (!node) - return false; - - choice = asn1_find_node (node, field); - return_val_if_fail (choice != NULL, false); - - len = sizeof (buf) - 1; - ret = asn1_read_value (node, field, buf, &len); - return_val_if_fail (ret == ASN1_SUCCESS, false); - - sub = strconcat (field, ".", buf, NULL); - - /* - * So here we take a shortcut and just copy the date from the - * certificate into the CK_DATE. This doesn't take into account - * time zones. However the PKCS#11 spec does not say what timezone - * the dates are in. In the PKCS#11 value have a day resolution, - * and time zones aren't that critical. - */ - - if (strcmp (buf, "generalTime") == 0) { - len = sizeof (buf) - 1; - ret = asn1_read_value (node, sub, buf, &len); - return_val_if_fail (ret == ASN1_SUCCESS, false); - return_val_if_fail (len >= 8, false); - - /* Same as first 8 characters of date */ - memcpy (date, buf, 8); - - } else if (strcmp (buf, "utcTime") == 0) { - len = sizeof (buf) - 1; - ret = asn1_read_value (node, sub, buf, &len); - return_val_if_fail (ret == ASN1_SUCCESS, false); - return_val_if_fail (len >= 6, false); - - year = atoin (buf, 2); - return_val_if_fail (year >= 0, false); - - century = century_for_two_digit_year (year); - return_val_if_fail (century >= 0, false); - - snprintf ((char *)date->year, 3, "%02d", century); - memcpy (((char *)date) + 2, buf, 6); - - } else { - return_val_if_reached (false); - } - - free (sub); - return true; -} - -static bool -calc_element (node_asn *node, - const unsigned char *data, - size_t length, - const char *field, - CK_ATTRIBUTE *attr) -{ - int ret; - int start, end; - - if (!node) - return false; - - ret = asn1_der_decoding_startEnd (node, data, length, field, &start, &end); - return_val_if_fail (ret == ASN1_SUCCESS, false); - return_val_if_fail (end >= start, false); - - attr->pValue = (void *)(data + start); - attr->ulValueLen = (end - start) + 1; - return true; -} - -static bool -is_v1_x509_authority (p11_builder *builder, - CK_ATTRIBUTE *cert) -{ - CK_ATTRIBUTE subject; - CK_ATTRIBUTE issuer; - CK_ATTRIBUTE *value; - char buffer[16]; - node_asn *node; - int len; - int ret; - - value = p11_attrs_find_valid (cert, CKA_VALUE); - if (value == NULL) - return false; - - node = decode_or_get_asn1 (builder, "PKIX1.Certificate", - value->pValue, value->ulValueLen); - return_val_if_fail (node != NULL, false); - - len = sizeof (buffer); - ret = asn1_read_value (node, "tbsCertificate.version", buffer, &len); - - /* The default value */ - if (ret == ASN1_ELEMENT_NOT_FOUND) { - ret = ASN1_SUCCESS; - buffer[0] = 0; - len = 1; - } - - return_val_if_fail (ret == ASN1_SUCCESS, false); - - /* - * In X.509 version v1 is the integer zero. Two's complement - * integer, but zero is easy to read. - */ - if (len != 1 || buffer[0] != 0) - return false; - - /* Must be self-signed, ie: same subject and issuer */ - if (!calc_element (node, value->pValue, value->ulValueLen, "tbsCertificate.subject", &subject)) - return_val_if_reached (false); - if (!calc_element (node, value->pValue, value->ulValueLen, "tbsCertificate.issuer", &issuer)) - return_val_if_reached (false); - return p11_attr_match_value (&subject, issuer.pValue, issuer.ulValueLen); -} - -static bool -calc_certificate_category (p11_builder *builder, - p11_index *index, - CK_ATTRIBUTE *cert, - CK_ATTRIBUTE *public_key, - CK_ULONG *category) -{ - CK_ATTRIBUTE *label; - unsigned char *ext; - size_t ext_len; - bool is_ca = 0; - bool ret; - - /* - * In the PKCS#11 spec: - * 0 = unspecified (default value) - * 1 = token user - * 2 = authority - * 3 = other entity - */ - - /* See if we have a basic constraints extension */ - ext = lookup_extension (builder, index, cert, public_key, P11_OID_BASIC_CONSTRAINTS, &ext_len); - if (ext != NULL) { - ret = p11_x509_parse_basic_constraints (builder->asn1_defs, ext, ext_len, &is_ca); - free (ext); - if (!ret) { - label = p11_attrs_find_valid (cert, CKA_LABEL); - p11_message ("%.*s: invalid basic constraints certificate extension", - label ? (int)label->ulValueLen : 7, - label ? (char *)label->pValue : "unknown"); - return false; - } - - } else if (is_v1_x509_authority (builder, cert)) { - /* - * If there is no basic constraints extension, and the CA version is - * v1, and is self-signed, then we assume this is a certificate authority. - * So we add a BasicConstraints attached certificate extension - */ - is_ca = 1; - - } else if (!p11_attrs_find_valid (cert, CKA_VALUE)) { - /* - * If we have no certificate value, then this is unknown - */ - *category = 0; - return true; - - } - - *category = is_ca ? 2 : 3; - return true; -} - -static CK_ATTRIBUTE * -certificate_value_attrs (p11_builder *builder, - CK_ATTRIBUTE *attrs, - node_asn *node, - const unsigned char *der, - size_t der_len, - CK_ATTRIBUTE *public_key) -{ - unsigned char checksum[P11_DIGEST_SHA1_LEN]; - unsigned char *keyid = NULL; - size_t keyid_len; - unsigned char *ext = NULL; - size_t ext_len; - CK_BBOOL falsev = CK_FALSE; - CK_ULONG zero = 0UL; - CK_BYTE checkv[3]; - CK_DATE startv; - CK_DATE endv; - char *labelv = NULL; - - CK_ATTRIBUTE trusted = { CKA_TRUSTED, &falsev, sizeof (falsev) }; - CK_ATTRIBUTE distrusted = { CKA_X_DISTRUSTED, &falsev, sizeof (falsev) }; - CK_ATTRIBUTE url = { CKA_URL, "", 0 }; - CK_ATTRIBUTE hash_of_subject_public_key = { CKA_HASH_OF_SUBJECT_PUBLIC_KEY, checksum, sizeof (checksum) }; - CK_ATTRIBUTE hash_of_issuer_public_key = { CKA_HASH_OF_ISSUER_PUBLIC_KEY, "", 0 }; - CK_ATTRIBUTE java_midp_security_domain = { CKA_JAVA_MIDP_SECURITY_DOMAIN, &zero, sizeof (zero) }; - CK_ATTRIBUTE check_value = { CKA_CHECK_VALUE, &checkv, sizeof (checkv) }; - CK_ATTRIBUTE start_date = { CKA_START_DATE, &startv, sizeof (startv) }; - CK_ATTRIBUTE end_date = { CKA_END_DATE, &endv, sizeof (endv) }; - CK_ATTRIBUTE subject = { CKA_SUBJECT, }; - CK_ATTRIBUTE issuer = { CKA_ISSUER, "", 0 }; - CK_ATTRIBUTE serial_number = { CKA_SERIAL_NUMBER, "", 0 }; - CK_ATTRIBUTE label = { CKA_LABEL }; - CK_ATTRIBUTE id = { CKA_ID, NULL, 0 }; - - return_val_if_fail (attrs != NULL, NULL); - - if (der == NULL) - check_value.type = CKA_INVALID; - else - calc_check_value (der, der_len, checkv); - - if (!calc_date (node, "tbsCertificate.validity.notBefore", &startv)) - start_date.ulValueLen = 0; - if (!calc_date (node, "tbsCertificate.validity.notAfter", &endv)) - end_date.ulValueLen = 0; - - if (calc_element (node, der, der_len, "tbsCertificate.subjectPublicKeyInfo", public_key)) - public_key->type = CKA_PUBLIC_KEY_INFO; - else - public_key->type = CKA_INVALID; - calc_element (node, der, der_len, "tbsCertificate.issuer.rdnSequence", &issuer); - if (!calc_element (node, der, der_len, "tbsCertificate.subject.rdnSequence", &subject)) - subject.type = CKA_INVALID; - calc_element (node, der, der_len, "tbsCertificate.serialNumber", &serial_number); - - /* Try to build a keyid from an extension */ - if (node) { - ext = p11_x509_find_extension (node, P11_OID_SUBJECT_KEY_IDENTIFIER, der, der_len, &ext_len); - if (ext) { - keyid = p11_x509_parse_subject_key_identifier (builder->asn1_defs, ext, - ext_len, &keyid_len); - id.pValue = keyid; - id.ulValueLen = keyid_len; - } - } - - if (!node || !p11_x509_hash_subject_public_key (node, der, der_len, checksum)) - hash_of_subject_public_key.ulValueLen = 0; - - if (id.pValue == NULL) { - id.pValue = hash_of_subject_public_key.pValue; - id.ulValueLen = hash_of_subject_public_key.ulValueLen; - } - - if (node) { - labelv = p11_x509_lookup_dn_name (node, "tbsCertificate.subject", - der, der_len, P11_OID_CN); - if (!labelv) - labelv = p11_x509_lookup_dn_name (node, "tbsCertificate.subject", - der, der_len, P11_OID_OU); - if (!labelv) - labelv = p11_x509_lookup_dn_name (node, "tbsCertificate.subject", - der, der_len, P11_OID_O); - } - - if (labelv) { - label.pValue = labelv; - label.ulValueLen = strlen (labelv); - } else { - label.type = CKA_INVALID; - } - - attrs = p11_attrs_build (attrs, &trusted, &distrusted, &url, &hash_of_issuer_public_key, - &hash_of_subject_public_key, &java_midp_security_domain, - &check_value, &start_date, &end_date, &id, - &subject, &issuer, &serial_number, &label, public_key, - NULL); - return_val_if_fail (attrs != NULL, NULL); - - free (ext); - free (keyid); - free (labelv); - return attrs; -} - -static CK_ATTRIBUTE * -certificate_populate (p11_builder *builder, - p11_index *index, - CK_ATTRIBUTE *cert) -{ - CK_ULONG categoryv = 0UL; - CK_ATTRIBUTE *attrs = NULL; - CK_ATTRIBUTE public_key; - node_asn *node = NULL; - unsigned char *der = NULL; - size_t der_len = 0; - - CK_ATTRIBUTE category = { CKA_CERTIFICATE_CATEGORY, &categoryv, sizeof (categoryv) }; - CK_ATTRIBUTE empty_value = { CKA_VALUE, "", 0 }; - - attrs = common_populate (builder, index, cert); - return_val_if_fail (attrs != NULL, NULL); - - der = p11_attrs_find_value (cert, CKA_VALUE, &der_len); - if (der != NULL) - node = decode_or_get_asn1 (builder, "PKIX1.Certificate", der, der_len); - - attrs = certificate_value_attrs (builder, attrs, node, der, der_len, &public_key); - return_val_if_fail (attrs != NULL, NULL); - - if (!calc_certificate_category (builder, index, cert, &public_key, &categoryv)) - categoryv = 0; - - return p11_attrs_build (attrs, &category, &empty_value, NULL); -} - -static bool -have_attribute (CK_ATTRIBUTE *attrs1, - CK_ATTRIBUTE *attrs2, - CK_ATTRIBUTE_TYPE type) -{ - CK_ATTRIBUTE *attr; - - attr = p11_attrs_find (attrs1, type); - if (attr == NULL) - attr = p11_attrs_find (attrs2, type); - return attr != NULL && attr->ulValueLen > 0; -} - -static CK_RV -certificate_validate (p11_builder *builder, - CK_ATTRIBUTE *attrs, - CK_ATTRIBUTE *merge) -{ - /* - * In theory we should be validating that in the absence of CKA_VALUE - * various other fields must be set. However we do not enforce this - * because we want to be able to have certificates without a value - * but issuer and serial number, for blacklisting purposes. - */ - - if (have_attribute (attrs, merge, CKA_URL)) { - if (!have_attribute (attrs, merge, CKA_HASH_OF_SUBJECT_PUBLIC_KEY)) { - p11_message ("missing the CKA_HASH_OF_SUBJECT_PUBLIC_KEY attribute"); - return CKR_TEMPLATE_INCONSISTENT; - } - - if (!have_attribute (attrs, merge, CKA_HASH_OF_SUBJECT_PUBLIC_KEY)) { - p11_message ("missing the CKA_HASH_OF_ISSUER_PUBLIC_KEY attribute"); - return CKR_TEMPLATE_INCONSISTENT; - } - } - - return CKR_OK; -} - -const static builder_schema certificate_schema = { - NORMAL_BUILD, - { COMMON_ATTRS, - { CKA_CERTIFICATE_TYPE, REQUIRE | CREATE, type_ulong }, - { CKA_TRUSTED, CREATE | WANT, type_bool }, - { CKA_X_DISTRUSTED, CREATE | WANT, type_bool }, - { CKA_CERTIFICATE_CATEGORY, CREATE | WANT, type_ulong }, - { CKA_CHECK_VALUE, CREATE | WANT, }, - { CKA_START_DATE, CREATE | MODIFY | WANT, type_date }, - { CKA_END_DATE, CREATE | MODIFY | WANT, type_date }, - { CKA_SUBJECT, CREATE | WANT, type_der_name }, - { CKA_ID, CREATE | MODIFY | WANT }, - { CKA_ISSUER, CREATE | MODIFY | WANT, type_der_name }, - { CKA_SERIAL_NUMBER, CREATE | MODIFY | WANT, type_der_serial }, - { CKA_VALUE, CREATE, type_der_cert }, - { CKA_URL, CREATE, type_utf8 }, - { CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CREATE }, - { CKA_HASH_OF_ISSUER_PUBLIC_KEY, CREATE }, - { CKA_JAVA_MIDP_SECURITY_DOMAIN, CREATE, type_ulong }, - { CKA_PUBLIC_KEY_INFO, WANT, type_der_key }, - { CKA_INVALID }, - }, certificate_populate, certificate_validate, -}; - -static CK_ATTRIBUTE * -extension_populate (p11_builder *builder, - p11_index *index, - CK_ATTRIBUTE *extension) -{ - unsigned char checksum[P11_DIGEST_SHA1_LEN]; - CK_ATTRIBUTE object_id = { CKA_INVALID }; - CK_ATTRIBUTE id = { CKA_INVALID }; - CK_ATTRIBUTE *attrs = NULL; - - void *der; - size_t len; - node_asn *asn; - - attrs = common_populate (builder, index, extension); - return_val_if_fail (attrs != NULL, NULL); - - if (!p11_attrs_find_valid (attrs, CKA_ID)) { - der = p11_attrs_find_value (extension, CKA_PUBLIC_KEY_INFO, &len); - return_val_if_fail (der != NULL, NULL); - - p11_digest_sha1 (checksum, der, len, NULL); - id.pValue = checksum; - id.ulValueLen = sizeof (checksum); - id.type = CKA_ID; - } - - /* Pull the object id out of the extension if not present */ - if (!p11_attrs_find_valid (attrs, CKA_OBJECT_ID)) { - der = p11_attrs_find_value (extension, CKA_VALUE, &len); - return_val_if_fail (der != NULL, NULL); - - asn = decode_or_get_asn1 (builder, "PKIX1.Extension", der, len); - return_val_if_fail (asn != NULL, NULL); - - if (calc_element (asn, der, len, "extnID", &object_id)) - object_id.type = CKA_OBJECT_ID; - } - - attrs = p11_attrs_build (attrs, &object_id, &id, NULL); - return_val_if_fail (attrs != NULL, NULL); - - return attrs; -} - -const static builder_schema extension_schema = { - NORMAL_BUILD, - { COMMON_ATTRS, - { CKA_VALUE, REQUIRE | CREATE, type_der_ext }, - { CKA_PUBLIC_KEY_INFO, REQUIRE | CREATE, type_der_key }, - { CKA_OBJECT_ID, CREATE | WANT, type_der_oid }, - { CKA_ID, CREATE | MODIFY }, - { CKA_INVALID }, - }, extension_populate, -}; - -static CK_ATTRIBUTE * -data_populate (p11_builder *builder, - p11_index *index, - CK_ATTRIBUTE *data) -{ - static const CK_ATTRIBUTE value = { CKA_VALUE, "", 0 }; - static const CK_ATTRIBUTE application = { CKA_APPLICATION, "", 0 }; - static const CK_ATTRIBUTE object_id = { CKA_OBJECT_ID, "", 0 }; - CK_ATTRIBUTE *attrs; - - attrs = common_populate (builder, index, data); - return_val_if_fail (attrs != NULL, NULL); - - return p11_attrs_build (attrs, &value, &application, &object_id, NULL); -} - -const static builder_schema data_schema = { - NORMAL_BUILD, - { COMMON_ATTRS, - { CKA_VALUE, CREATE | MODIFY | WANT }, - { CKA_APPLICATION, CREATE | MODIFY | WANT, type_utf8 }, - { CKA_OBJECT_ID, CREATE | MODIFY | WANT, type_der_oid }, - { CKA_INVALID }, - }, data_populate, -}; - -const static builder_schema trust_schema = { - GENERATED_CLASS, - { COMMON_ATTRS, - { CKA_CERT_SHA1_HASH, CREATE }, - { CKA_CERT_MD5_HASH, CREATE }, - { CKA_ISSUER, CREATE }, - { CKA_SUBJECT, CREATE }, - { CKA_SERIAL_NUMBER, CREATE }, - { CKA_TRUST_SERVER_AUTH, CREATE }, - { CKA_TRUST_CLIENT_AUTH, CREATE }, - { CKA_TRUST_EMAIL_PROTECTION, CREATE }, - { CKA_TRUST_CODE_SIGNING, CREATE }, - { CKA_TRUST_IPSEC_END_SYSTEM, CREATE }, - { CKA_TRUST_IPSEC_TUNNEL, CREATE }, - { CKA_TRUST_IPSEC_USER, CREATE }, - { CKA_TRUST_TIME_STAMPING, CREATE }, - { CKA_TRUST_DIGITAL_SIGNATURE, CREATE }, - { CKA_TRUST_NON_REPUDIATION, CREATE }, - { CKA_TRUST_KEY_ENCIPHERMENT, CREATE }, - { CKA_TRUST_DATA_ENCIPHERMENT, CREATE }, - { CKA_TRUST_KEY_AGREEMENT, CREATE }, - { CKA_TRUST_KEY_CERT_SIGN, CREATE }, - { CKA_TRUST_CRL_SIGN, CREATE }, - { CKA_TRUST_STEP_UP_APPROVED, CREATE }, - { CKA_ID, CREATE }, - { CKA_INVALID }, - }, common_populate -}; - -const static builder_schema assertion_schema = { - GENERATED_CLASS, - { COMMON_ATTRS, - { CKA_X_PURPOSE, REQUIRE | CREATE }, - { CKA_X_CERTIFICATE_VALUE, CREATE }, - { CKA_X_ASSERTION_TYPE, REQUIRE | CREATE }, - { CKA_ISSUER, CREATE }, - { CKA_SERIAL_NUMBER, CREATE }, - { CKA_X_PEER, CREATE }, - { CKA_ID, CREATE }, - { CKA_INVALID }, - }, common_populate -}; - -const static builder_schema builtin_schema = { - GENERATED_CLASS, - { COMMON_ATTRS, - { CKA_INVALID }, - }, common_populate -}; - -static const char * -value_name (const p11_constant *info, - CK_ATTRIBUTE_TYPE type) -{ - const char *name = p11_constant_name (info, type); - return name ? name : "unknown"; -} - -static const char * -type_name (CK_ATTRIBUTE_TYPE type) -{ - return value_name (p11_constant_types, type); -} - -static CK_RV -build_for_schema (p11_builder *builder, - p11_index *index, - const builder_schema *schema, - CK_ATTRIBUTE *attrs, - CK_ATTRIBUTE *merge, - CK_ATTRIBUTE **extra) -{ - CK_BBOOL modifiable; - CK_ATTRIBUTE *attr; - bool modifying; - bool creating; - bool populate; - bool loading; - bool found; - int flags; - int i, j; - CK_RV rv; - - populate = false; - - /* Signifies that data is being loaded */ - loading = p11_index_loading (index); - - /* Signifies that this is being created by a caller, instead of loaded */ - creating = (attrs == NULL && !loading); - - /* Item is being modified by a caller */ - modifying = (attrs != NULL && !loading); - - /* This item may not be modifiable */ - if (modifying) { - if (!p11_attrs_find_bool (attrs, CKA_MODIFIABLE, &modifiable) || !modifiable) { - p11_message ("the object is not modifiable"); - return CKR_ATTRIBUTE_READ_ONLY; - } - } - - if (creating && (builder->flags & P11_BUILDER_FLAG_TOKEN)) { - if (schema->build_flags & GENERATED_CLASS) { - p11_message ("objects of this type cannot be created"); - return CKR_TEMPLATE_INCONSISTENT; - } - } - - for (i = 0; merge[i].type != CKA_INVALID; i++) { - - /* Don't validate attribute if not changed */ - attr = p11_attrs_find (attrs, merge[i].type); - if (attr && p11_attr_equal (attr, merge + i)) - continue; - - found = false; - for (j = 0; schema->attrs[j].type != CKA_INVALID; j++) { - if (schema->attrs[j].type != merge[i].type) - continue; - - flags = schema->attrs[j].flags; - if (creating && !(flags & CREATE)) { - p11_message ("the %s attribute cannot be set", - type_name (schema->attrs[j].type)); - return CKR_ATTRIBUTE_READ_ONLY; - } - if (modifying && !(flags & MODIFY)) { - p11_message ("the %s attribute cannot be changed", - type_name (schema->attrs[j].type)); - return CKR_ATTRIBUTE_READ_ONLY; - } - if (!loading && schema->attrs[j].validate != NULL && - !schema->attrs[j].validate (builder, merge + i)) { - p11_message ("the %s attribute has an invalid value", - type_name (schema->attrs[j].type)); - return CKR_ATTRIBUTE_VALUE_INVALID; - } - found = true; - break; - } - - if (!found) { - p11_message ("the %s attribute is not valid for the object", - type_name (merge[i].type)); - return CKR_TEMPLATE_INCONSISTENT; - } - } - - if (attrs == NULL) { - for (j = 0; schema->attrs[j].type != CKA_INVALID; j++) { - flags = schema->attrs[j].flags; - found = false; - - if ((flags & REQUIRE) || (flags & WANT)) { - for (i = 0; merge[i].type != CKA_INVALID; i++) { - if (schema->attrs[j].type == merge[i].type) { - found = true; - break; - } - } - } - - if (!found) { - if (flags & REQUIRE) { - p11_message ("missing the %s attribute", - type_name (schema->attrs[j].type)); - return CKR_TEMPLATE_INCOMPLETE; - } else if (flags & WANT) { - populate = true; - } - } - } - } - - /* Validate the result, before committing to the change. */ - if (!loading && schema->validate) { - rv = (schema->validate) (builder, attrs, merge); - if (rv != CKR_OK) - return rv; - } - - if (populate && schema->populate) - *extra = schema->populate (builder, index, merge); - - return CKR_OK; -} - -CK_RV -p11_builder_build (void *bilder, - p11_index *index, - CK_ATTRIBUTE *attrs, - CK_ATTRIBUTE *merge, - CK_ATTRIBUTE **populate) -{ - p11_builder *builder = bilder; - CK_OBJECT_CLASS klass; - CK_CERTIFICATE_TYPE type; - CK_BBOOL token; - - return_val_if_fail (builder != NULL, CKR_GENERAL_ERROR); - return_val_if_fail (index != NULL, CKR_GENERAL_ERROR); - return_val_if_fail (merge != NULL, CKR_GENERAL_ERROR); - - if (!p11_attrs_find_ulong (attrs ? attrs : merge, CKA_CLASS, &klass)) { - p11_message ("no CKA_CLASS attribute found"); - return CKR_TEMPLATE_INCOMPLETE; - } - - if (!attrs && p11_attrs_find_bool (merge, CKA_TOKEN, &token)) { - if (token != ((builder->flags & P11_BUILDER_FLAG_TOKEN) ? CK_TRUE : CK_FALSE)) { - p11_message ("cannot create a %s object", token ? "token" : "non-token"); - return CKR_TEMPLATE_INCONSISTENT; - } - } - - switch (klass) { - case CKO_CERTIFICATE: - if (!p11_attrs_find_ulong (attrs ? attrs : merge, CKA_CERTIFICATE_TYPE, &type)) { - p11_message ("missing %s on object", type_name (CKA_CERTIFICATE_TYPE)); - return CKR_TEMPLATE_INCOMPLETE; - } else if (type == CKC_X_509) { - return build_for_schema (builder, index, &certificate_schema, attrs, merge, populate); - } else { - p11_message ("%s unsupported %s", value_name (p11_constant_certs, type), - type_name (CKA_CERTIFICATE_TYPE)); - return CKR_TEMPLATE_INCONSISTENT; - } - - case CKO_X_CERTIFICATE_EXTENSION: - return build_for_schema (builder, index, &extension_schema, attrs, merge, populate); - - case CKO_DATA: - return build_for_schema (builder, index, &data_schema, attrs, merge, populate); - - case CKO_NSS_TRUST: - return build_for_schema (builder, index, &trust_schema, attrs, merge, populate); - - case CKO_NSS_BUILTIN_ROOT_LIST: - return build_for_schema (builder, index, &builtin_schema, attrs, merge, populate); - - case CKO_X_TRUST_ASSERTION: - return build_for_schema (builder, index, &assertion_schema, attrs, merge, populate); - - default: - p11_message ("%s unsupported object class", - value_name (p11_constant_classes, klass)); - return CKR_TEMPLATE_INCONSISTENT; - } -} - -void -p11_builder_free (p11_builder *builder) -{ - return_if_fail (builder != NULL); - - p11_asn1_cache_free (builder->asn1_cache); - free (builder); -} - -p11_asn1_cache * -p11_builder_get_cache (p11_builder *builder) -{ - return_val_if_fail (builder != NULL, NULL); - return builder->asn1_cache; -} - -static CK_ATTRIBUTE * -build_trust_object_ku (p11_builder *builder, - p11_index *index, - CK_ATTRIBUTE *cert, - CK_ATTRIBUTE *object, - CK_TRUST present) -{ - unsigned char *data = NULL; - unsigned int ku = 0; - size_t length; - CK_TRUST defawlt; - CK_ULONG i; - - struct { - CK_ATTRIBUTE_TYPE type; - unsigned int ku; - } ku_attribute_map[] = { - { CKA_TRUST_DIGITAL_SIGNATURE, P11_KU_DIGITAL_SIGNATURE }, - { CKA_TRUST_NON_REPUDIATION, P11_KU_NON_REPUDIATION }, - { CKA_TRUST_KEY_ENCIPHERMENT, P11_KU_KEY_ENCIPHERMENT }, - { CKA_TRUST_DATA_ENCIPHERMENT, P11_KU_DATA_ENCIPHERMENT }, - { CKA_TRUST_KEY_AGREEMENT, P11_KU_KEY_AGREEMENT }, - { CKA_TRUST_KEY_CERT_SIGN, P11_KU_KEY_CERT_SIGN }, - { CKA_TRUST_CRL_SIGN, P11_KU_CRL_SIGN }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE attrs[sizeof (ku_attribute_map)]; - - defawlt = present; - - /* If blacklisted, don't even bother looking at extensions */ - if (present != CKT_NSS_NOT_TRUSTED) - data = lookup_extension (builder, index, cert, NULL, P11_OID_KEY_USAGE, &length); - - if (data) { - /* - * If the certificate extension was missing, then *all* key - * usages are to be set. If the extension was invalid, then - * fail safe to none of the key usages. - */ - defawlt = CKT_NSS_TRUST_UNKNOWN; - - if (!p11_x509_parse_key_usage (builder->asn1_defs, data, length, &ku)) - p11_message ("invalid key usage certificate extension"); - free (data); - } - - for (i = 0; ku_attribute_map[i].type != CKA_INVALID; i++) { - attrs[i].type = ku_attribute_map[i].type; - if (data && (ku & ku_attribute_map[i].ku) == ku_attribute_map[i].ku) { - attrs[i].pValue = &present; - attrs[i].ulValueLen = sizeof (present); - } else { - attrs[i].pValue = &defawlt; - attrs[i].ulValueLen = sizeof (defawlt); - } - } - - return p11_attrs_buildn (object, attrs, i); -} - -static bool -strv_to_dict (const char **array, - p11_dict **dict) -{ - int i; - - if (!array) { - *dict = NULL; - return true; - } - - *dict = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, NULL); - return_val_if_fail (*dict != NULL, false); - - for (i = 0; array[i] != NULL; i++) { - if (!p11_dict_set (*dict, (void *)array[i], (void *)array[i])) - return_val_if_reached (false); - } - - return true; -} - -static CK_ATTRIBUTE * -build_trust_object_eku (CK_ATTRIBUTE *object, - CK_TRUST allow, - const char **purposes, - const char **rejects) -{ - p11_dict *dict_purp; - p11_dict *dict_rej; - CK_TRUST neutral; - CK_TRUST disallow; - CK_ULONG i; - - struct { - CK_ATTRIBUTE_TYPE type; - const char *oid; - } eku_attribute_map[] = { - { CKA_TRUST_SERVER_AUTH, P11_OID_SERVER_AUTH_STR }, - { CKA_TRUST_CLIENT_AUTH, P11_OID_CLIENT_AUTH_STR }, - { CKA_TRUST_CODE_SIGNING, P11_OID_CODE_SIGNING_STR }, - { CKA_TRUST_EMAIL_PROTECTION, P11_OID_EMAIL_PROTECTION_STR }, - { CKA_TRUST_IPSEC_END_SYSTEM, P11_OID_IPSEC_END_SYSTEM_STR }, - { CKA_TRUST_IPSEC_TUNNEL, P11_OID_IPSEC_TUNNEL_STR }, - { CKA_TRUST_IPSEC_USER, P11_OID_IPSEC_USER_STR }, - { CKA_TRUST_TIME_STAMPING, P11_OID_TIME_STAMPING_STR }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE attrs[sizeof (eku_attribute_map)]; - - if (!strv_to_dict (purposes, &dict_purp) || - !strv_to_dict (rejects, &dict_rej)) - return_val_if_reached (NULL); - - /* The neutral value is set if an purpose is not present */ - if (allow == CKT_NSS_NOT_TRUSTED) - neutral = CKT_NSS_NOT_TRUSTED; - - /* If anything explicitly set, then neutral is unknown */ - else if (purposes || rejects) - neutral = CKT_NSS_TRUST_UNKNOWN; - - /* Otherwise neutral will allow any purpose */ - else - neutral = allow; - - /* The value set if a purpose is explicitly rejected */ - disallow = CKT_NSS_NOT_TRUSTED; - - for (i = 0; eku_attribute_map[i].type != CKA_INVALID; i++) { - attrs[i].type = eku_attribute_map[i].type; - if (dict_rej && p11_dict_get (dict_rej, eku_attribute_map[i].oid)) { - attrs[i].pValue = &disallow; - attrs[i].ulValueLen = sizeof (disallow); - } else if (dict_purp && p11_dict_get (dict_purp, eku_attribute_map[i].oid)) { - attrs[i].pValue = &allow; - attrs[i].ulValueLen = sizeof (allow); - } else { - attrs[i].pValue = &neutral; - attrs[i].ulValueLen = sizeof (neutral); - } - } - - p11_dict_free (dict_purp); - p11_dict_free (dict_rej); - - return p11_attrs_buildn (object, attrs, i); -} - -static void -replace_nss_trust_object (p11_builder *builder, - p11_index *index, - CK_ATTRIBUTE *cert, - CK_BBOOL trust, - CK_BBOOL distrust, - CK_BBOOL authority, - const char **purposes, - const char **rejects) -{ - CK_ATTRIBUTE *attrs = NULL; - CK_ATTRIBUTE *match = NULL; - CK_TRUST allow; - CK_RV rv; - - CK_OBJECT_CLASS klassv = CKO_NSS_TRUST; - CK_BYTE sha1v[P11_DIGEST_SHA1_LEN]; - CK_BYTE md5v[P11_DIGEST_MD5_LEN]; - CK_BBOOL generatedv = CK_FALSE; - CK_BBOOL falsev = CK_FALSE; - - CK_ATTRIBUTE klass = { CKA_CLASS, &klassv, sizeof (klassv) }; - CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &falsev, sizeof (falsev) }; - CK_ATTRIBUTE generated = { CKA_X_GENERATED, &generatedv, sizeof (generatedv) }; - CK_ATTRIBUTE invalid = { CKA_INVALID, }; - - CK_ATTRIBUTE md5_hash = { CKA_CERT_MD5_HASH, md5v, sizeof (md5v) }; - CK_ATTRIBUTE sha1_hash = { CKA_CERT_SHA1_HASH, sha1v, sizeof (sha1v) }; - - CK_ATTRIBUTE step_up_approved = { CKA_TRUST_STEP_UP_APPROVED, &falsev, sizeof (falsev) }; - - CK_ATTRIBUTE_PTR label; - CK_ATTRIBUTE_PTR id; - CK_ATTRIBUTE_PTR subject; - CK_ATTRIBUTE_PTR issuer; - CK_ATTRIBUTE_PTR serial_number; - - p11_array *array; - void *value; - size_t length; - - issuer = p11_attrs_find_valid (cert, CKA_ISSUER); - serial_number = p11_attrs_find_valid (cert, CKA_SERIAL_NUMBER); - value = p11_attrs_find_value (cert, CKA_VALUE, &length); - - if (!issuer && !serial_number && !value) { - p11_debug ("can't generate nss trust object for certificate without issuer+serial or value"); - return; - } - - if (value == NULL) { - md5_hash.type = CKA_INVALID; - sha1_hash.type = CKA_INVALID; - } else { - p11_digest_md5 (md5v, value, length, NULL); - p11_digest_sha1 (sha1v, value, length, NULL); - } - if (!issuer) - issuer = &invalid; - if (!serial_number) - serial_number = &invalid; - - match = p11_attrs_build (NULL, issuer, serial_number, &sha1_hash, - &generated, &klass, NULL); - return_if_fail (match != NULL); - - /* If we find a non-generated object, then don't generate */ - if (p11_index_find (index, match, -1)) { - p11_debug ("not generating nss trust object because one already exists"); - attrs = NULL; - - } else { - generatedv = CK_TRUE; - match = p11_attrs_build (match, &generated, NULL); - return_if_fail (match != NULL); - - /* Copy all of the following attributes from certificate */ - id = p11_attrs_find_valid (cert, CKA_ID); - if (id == NULL) - id = &invalid; - subject = p11_attrs_find_valid (cert, CKA_SUBJECT); - if (subject == NULL) - subject = &invalid; - label = p11_attrs_find_valid (cert, CKA_LABEL); - if (label == NULL) - label = &invalid; - - attrs = p11_attrs_dup (match); - return_if_fail (attrs != NULL); - - attrs = p11_attrs_build (attrs, &klass, &modifiable, id, label, - subject, issuer, serial_number, - &md5_hash, &sha1_hash, &step_up_approved, NULL); - return_if_fail (attrs != NULL); - - /* Calculate the default allow trust */ - if (distrust) - allow = CKT_NSS_NOT_TRUSTED; - else if (trust && authority) - allow = CKT_NSS_TRUSTED_DELEGATOR; - else if (trust) - allow = CKT_NSS_TRUSTED; - else - allow = CKT_NSS_TRUST_UNKNOWN; - - attrs = build_trust_object_ku (builder, index, cert, attrs, allow); - return_if_fail (attrs != NULL); - - attrs = build_trust_object_eku (attrs, allow, purposes, rejects); - return_if_fail (attrs != NULL); - } - - /* Replace related generated object with this new one */ - array = p11_array_new (NULL); - p11_array_push (array, attrs); - rv = p11_index_replace_all (index, match, CKA_INVALID, array); - return_if_fail (rv == CKR_OK); - p11_array_free (array); - - p11_attrs_free (match); -} - -static void -build_assertions (p11_array *array, - CK_ATTRIBUTE *cert, - CK_X_ASSERTION_TYPE type, - const char **oids) -{ - CK_OBJECT_CLASS assertion = CKO_X_TRUST_ASSERTION; - CK_BBOOL truev = CK_TRUE; - CK_BBOOL falsev = CK_FALSE; - - CK_ATTRIBUTE klass = { CKA_CLASS, &assertion, sizeof (assertion) }; - CK_ATTRIBUTE private = { CKA_PRIVATE, &falsev, sizeof (falsev) }; - CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &falsev, sizeof (falsev) }; - CK_ATTRIBUTE assertion_type = { CKA_X_ASSERTION_TYPE, &type, sizeof (type) }; - CK_ATTRIBUTE autogen = { CKA_X_GENERATED, &truev, sizeof (truev) }; - CK_ATTRIBUTE purpose = { CKA_X_PURPOSE, }; - CK_ATTRIBUTE invalid = { CKA_INVALID, }; - CK_ATTRIBUTE certificate_value = { CKA_X_CERTIFICATE_VALUE, }; - - CK_ATTRIBUTE *issuer; - CK_ATTRIBUTE *serial; - CK_ATTRIBUTE *value; - CK_ATTRIBUTE *label; - CK_ATTRIBUTE *id; - CK_ATTRIBUTE *attrs; - int i; - - if (type == CKT_X_DISTRUSTED_CERTIFICATE) { - certificate_value.type = CKA_INVALID; - issuer = p11_attrs_find_valid (cert, CKA_ISSUER); - serial = p11_attrs_find_valid (cert, CKA_SERIAL_NUMBER); - - if (!issuer || !serial) { - p11_debug ("not building negative trust assertion for certificate without serial or issuer"); - return; - } - - } else { - issuer = &invalid; - serial = &invalid; - value = p11_attrs_find_valid (cert, CKA_VALUE); - - if (value == NULL) { - p11_debug ("not building positive trust assertion for certificate without value"); - return; - } - - certificate_value.pValue = value->pValue; - certificate_value.ulValueLen = value->ulValueLen; - } - - label = p11_attrs_find (cert, CKA_LABEL); - if (label == NULL) - label = &invalid; - id = p11_attrs_find (cert, CKA_ID); - if (id == NULL) - id = &invalid; - - for (i = 0; oids[i] != NULL; i++) { - purpose.pValue = (void *)oids[i]; - purpose.ulValueLen = strlen (oids[i]); - - attrs = p11_attrs_build (NULL, &klass, &private, &modifiable, - id, label, &assertion_type, &purpose, - issuer, serial, &certificate_value, &autogen, NULL); - return_if_fail (attrs != NULL); - - if (!p11_array_push (array, attrs)) - return_if_reached (); - } -} - -static void -build_trust_assertions (p11_array *positives, - p11_array *negatives, - CK_ATTRIBUTE *cert, - CK_BBOOL trust, - CK_BBOOL distrust, - CK_BBOOL authority, - const char **purposes, - const char **rejects) -{ - const char *all_purposes[] = { - P11_OID_SERVER_AUTH_STR, - P11_OID_CLIENT_AUTH_STR, - P11_OID_CODE_SIGNING_STR, - P11_OID_EMAIL_PROTECTION_STR, - P11_OID_IPSEC_END_SYSTEM_STR, - P11_OID_IPSEC_TUNNEL_STR, - P11_OID_IPSEC_USER_STR, - P11_OID_TIME_STAMPING_STR, - NULL, - }; - - /* Build assertions for anything that's explicitly rejected */ - if (rejects && negatives) { - build_assertions (negatives, cert, CKT_X_DISTRUSTED_CERTIFICATE, rejects); - } - - if (distrust && negatives) { - /* - * Trust assertions are defficient in that they don't blacklist a certificate - * for any purposes. So we just have to go wild and write out a bunch of - * assertions for all our known purposes. - */ - build_assertions (negatives, cert, CKT_X_DISTRUSTED_CERTIFICATE, all_purposes); - } - - /* - * TODO: Build pinned certificate assertions. That is, trusted - * certificates where not an authority. - */ - - if (trust && authority && positives) { - if (purposes) { - /* If purposes explicitly set, then anchor for those purposes */ - build_assertions (positives, cert, CKT_X_ANCHORED_CERTIFICATE, purposes); - } else { - /* If purposes not-explicitly set, then anchor for all known */ - build_assertions (positives, cert, CKT_X_ANCHORED_CERTIFICATE, all_purposes); - } - } -} - -static void -replace_trust_assertions (p11_builder *builder, - p11_index *index, - CK_ATTRIBUTE *cert, - CK_BBOOL trust, - CK_BBOOL distrust, - CK_BBOOL authority, - const char **purposes, - const char **rejects) -{ - CK_OBJECT_CLASS assertion = CKO_X_TRUST_ASSERTION; - CK_BBOOL generated = CK_TRUE; - p11_array *positives = NULL; - p11_array *negatives = NULL; - CK_ATTRIBUTE *value; - CK_ATTRIBUTE *issuer; - CK_ATTRIBUTE *serial; - CK_RV rv; - - CK_ATTRIBUTE match_positive[] = { - { CKA_X_CERTIFICATE_VALUE, }, - { CKA_CLASS, &assertion, sizeof (assertion) }, - { CKA_X_GENERATED, &generated, sizeof (generated) }, - { CKA_INVALID } - }; - - CK_ATTRIBUTE match_negative[] = { - { CKA_ISSUER, }, - { CKA_SERIAL_NUMBER, }, - { CKA_CLASS, &assertion, sizeof (assertion) }, - { CKA_X_GENERATED, &generated, sizeof (generated) }, - { CKA_INVALID } - }; - - value = p11_attrs_find_valid (cert, CKA_VALUE); - if (value) { - positives = p11_array_new (NULL); - match_positive[0].pValue = value->pValue; - match_positive[0].ulValueLen = value->ulValueLen; - } - - issuer = p11_attrs_find_valid (cert, CKA_ISSUER); - serial = p11_attrs_find_valid (cert, CKA_SERIAL_NUMBER); - if (issuer && serial) { - negatives = p11_array_new (NULL); - memcpy (match_negative + 0, issuer, sizeof (CK_ATTRIBUTE)); - memcpy (match_negative + 1, serial, sizeof (CK_ATTRIBUTE)); - } - - build_trust_assertions (positives, negatives, cert, trust, distrust, - authority, purposes, rejects); - - if (positives) { - rv = p11_index_replace_all (index, match_positive, CKA_X_PURPOSE, positives); - return_if_fail (rv == CKR_OK); - p11_array_free (positives); - } - - if (negatives) { - rv = p11_index_replace_all (index, match_negative, CKA_X_PURPOSE, negatives); - return_if_fail (rv == CKR_OK); - p11_array_free (negatives); - } -} - -static void -remove_trust_and_assertions (p11_builder *builder, - p11_index *index, - CK_ATTRIBUTE *attrs) -{ - replace_nss_trust_object (builder, index, attrs, - CK_FALSE, CK_FALSE, CK_FALSE, - NULL, NULL); - replace_trust_assertions (builder, index, attrs, - CK_FALSE, CK_FALSE, CK_FALSE, - NULL, NULL); -} - -static void -replace_trust_and_assertions (p11_builder *builder, - p11_index *index, - CK_ATTRIBUTE *cert) -{ - CK_BBOOL trust = CK_FALSE; - CK_BBOOL distrust = CK_FALSE; - CK_BBOOL authority = CK_FALSE; - p11_array *purposes = NULL; - p11_array *rejects = NULL; - const char **purposev; - const char **rejectv; - CK_ULONG category; - unsigned char *ext; - size_t ext_len; - - /* - * We look up all this information in advance, since it's used - * by the various adapter objects, and we don't have to parse - * it multiple times. - */ - - if (!p11_attrs_find_bool (cert, CKA_TRUSTED, &trust)) - trust = CK_FALSE; - if (!p11_attrs_find_bool (cert, CKA_X_DISTRUSTED, &distrust)) - distrust = CK_FALSE; - if (p11_attrs_find_ulong (cert, CKA_CERTIFICATE_CATEGORY, &category) && category == 2) - authority = CK_TRUE; - - if (!distrust) { - ext = lookup_extension (builder, index, cert, NULL, P11_OID_EXTENDED_KEY_USAGE, &ext_len); - if (ext != NULL) { - purposes = p11_x509_parse_extended_key_usage (builder->asn1_defs, ext, ext_len); - if (purposes == NULL) - p11_message ("invalid extended key usage certificate extension"); - free (ext); - } - - ext = lookup_extension (builder, index, cert, NULL, P11_OID_OPENSSL_REJECT, &ext_len); - if (ext != NULL) { - rejects = p11_x509_parse_extended_key_usage (builder->asn1_defs, ext, ext_len); - if (rejects == NULL) - p11_message ("invalid reject key usage certificate extension"); - free (ext); - } - } - - /* null-terminate these arrays and use as strv's */ - purposev = rejectv = NULL; - if (rejects) { - if (!p11_array_push (rejects, NULL)) - return_if_reached (); - rejectv = (const char **)rejects->elem; - } - if (purposes) { - if (!p11_array_push (purposes, NULL)) - return_if_reached (); - purposev = (const char **)purposes->elem; - } - - replace_nss_trust_object (builder, index, cert, trust, distrust, - authority, purposev, rejectv); - replace_trust_assertions (builder, index, cert, trust, distrust, - authority, purposev, rejectv); - - p11_array_free (purposes); - p11_array_free (rejects); -} - -static void -replace_compat_for_cert (p11_builder *builder, - p11_index *index, - CK_OBJECT_HANDLE handle, - CK_ATTRIBUTE *attrs) -{ - static const CK_OBJECT_CLASS certificate = CKO_CERTIFICATE; - static const CK_CERTIFICATE_TYPE x509 = CKC_X_509; - CK_ATTRIBUTE *value; - - CK_ATTRIBUTE match[] = { - { CKA_VALUE, }, - { CKA_CLASS, (void *)&certificate, sizeof (certificate) }, - { CKA_CERTIFICATE_TYPE, (void *)&x509, sizeof (x509) }, - { CKA_INVALID } - }; - - /* - * If this certificate is going away, then find duplicate. In this - * case all the trust assertions are recalculated with this new - * certificate in mind. - */ - if (handle == 0) { - value = p11_attrs_find_valid (attrs, CKA_VALUE); - if (value != NULL) { - match[0].pValue = value->pValue; - match[0].ulValueLen = value->ulValueLen; - handle = p11_index_find (index, match, -1); - } - if (handle != 0) - attrs = p11_index_lookup (index, handle); - } - - if (handle == 0) - remove_trust_and_assertions (builder, index, attrs); - else - replace_trust_and_assertions (builder, index, attrs); -} - -static void -replace_compat_for_ext (p11_builder *builder, - p11_index *index, - CK_OBJECT_HANDLE handle, - CK_ATTRIBUTE *attrs) -{ - - CK_OBJECT_HANDLE *handles; - CK_ATTRIBUTE *public_key; - int i; - - public_key = p11_attrs_find_valid (attrs, CKA_PUBLIC_KEY_INFO); - if (public_key == NULL) - return; - - handles = lookup_related (index, CKO_CERTIFICATE, public_key); - for (i = 0; handles && handles[i] != 0; i++) { - attrs = p11_index_lookup (index, handles[i]); - replace_trust_and_assertions (builder, index, attrs); - } - free (handles); -} - -static void -update_related_category (p11_builder *builder, - p11_index *index, - CK_OBJECT_HANDLE handle, - CK_ATTRIBUTE *attrs) -{ - CK_OBJECT_HANDLE *handles; - CK_ULONG categoryv = 0UL; - CK_ATTRIBUTE *update; - CK_ATTRIBUTE *cert; - CK_ATTRIBUTE *public_key; - CK_RV rv; - int i; - - CK_ATTRIBUTE category[] = { - { CKA_CERTIFICATE_CATEGORY, &categoryv, sizeof (categoryv) }, - { CKA_INVALID, }, - }; - - public_key = p11_attrs_find_valid (attrs, CKA_PUBLIC_KEY_INFO); - if (public_key == NULL) - return; - - /* Find all other objects with this handle */ - handles = lookup_related (index, CKO_CERTIFICATE, public_key); - - for (i = 0; handles && handles[i] != 0; i++) { - cert = p11_index_lookup (index, handle); - - if (calc_certificate_category (builder, index, cert, public_key, &categoryv)) { - update = p11_attrs_build (NULL, &category, NULL); - rv = p11_index_update (index, handles[i], update); - return_if_fail (rv == CKR_OK); - } - } - - free (handles); -} - -void -p11_builder_changed (void *bilder, - p11_index *index, - CK_OBJECT_HANDLE handle, - CK_ATTRIBUTE *attrs) -{ - static const CK_OBJECT_CLASS certificate = CKO_CERTIFICATE; - static const CK_OBJECT_CLASS extension = CKO_X_CERTIFICATE_EXTENSION; - static const CK_CERTIFICATE_TYPE x509 = CKC_X_509; - - static const CK_ATTRIBUTE match_cert[] = { - { CKA_CLASS, (void *)&certificate, sizeof (certificate) }, - { CKA_CERTIFICATE_TYPE, (void *)&x509, sizeof (x509) }, - { CKA_INVALID } - }; - - static const CK_ATTRIBUTE match_eku[] = { - { CKA_CLASS, (void *)&extension, sizeof (extension) }, - { CKA_OBJECT_ID, (void *)P11_OID_EXTENDED_KEY_USAGE, - sizeof (P11_OID_EXTENDED_KEY_USAGE) }, - { CKA_INVALID } - }; - - static const CK_ATTRIBUTE match_ku[] = { - { CKA_CLASS, (void *)&extension, sizeof (extension) }, - { CKA_OBJECT_ID, (void *)P11_OID_KEY_USAGE, - sizeof (P11_OID_KEY_USAGE) }, - { CKA_INVALID } - }; - - static const CK_ATTRIBUTE match_bc[] = { - { CKA_CLASS, (void *)&extension, sizeof (extension) }, - { CKA_OBJECT_ID, (void *)P11_OID_BASIC_CONSTRAINTS, - sizeof (P11_OID_BASIC_CONSTRAINTS) }, - { CKA_INVALID } - }; - - p11_builder *builder = bilder; - - return_if_fail (builder != NULL); - return_if_fail (index != NULL); - return_if_fail (attrs != NULL); - - /* - * Treat these operations as loading, not modifying/creating, so we get - * around many of the rules that govern object creation - */ - p11_index_load (index); - - /* A certificate */ - if (p11_attrs_match (attrs, match_cert)) { - replace_compat_for_cert (builder, index, handle, attrs); - - /* An ExtendedKeyUsage extension */ - } else if (p11_attrs_match (attrs, match_eku) || - p11_attrs_match (attrs, match_ku)) { - replace_compat_for_ext (builder, index, handle, attrs); - - /* A BasicConstraints extension */ - } else if (p11_attrs_match (attrs, match_bc)) { - update_related_category (builder, index, handle, attrs); - } - - p11_index_finish (index); -} -- cgit v1.2.1