diff --git a/lib/hx509/Makefile.am b/lib/hx509/Makefile.am new file mode 100644 index 000000000..d80fcf349 --- /dev/null +++ b/lib/hx509/Makefile.am @@ -0,0 +1,52 @@ +# $Id$ + +include $(top_srcdir)/Makefile.am.common + +lib_LTLIBRARIES = libhx509.la +libhx509_la_LDFLAGS = -version-info 1:0:0 + +BUILT_SOURCES = hx509_err.c hx509_err.h + +libhx509_la_LIBADD = ../asn1/libasn1.la + +libhx509_la_CPPFLAGS = -I$(srcdir)/ref $(INCLUDE_des) + +libhx509_la_SOURCES = \ + cert.c \ + cms.c \ + crypto.c \ + file.c \ + hx509.h \ + hx509_err.c \ + hx509_err.h \ + keyset.c \ + ks_mem.c \ + ks_file.c \ + ks_null.c \ + ks_p12.c \ + lock.c \ + name.c \ + p11.c \ + print.c + +$(libhx509_la_OBJECTS): $(srcdir)/hx509-protos.h $(srcdir)/hx509-private.h + +$(srcdir)/hx509-protos.h: + cd $(srcdir) && perl ../../cf/make-proto.pl -E HX509_LIB_FUNCTION -q -P comment -o hx509-protos.h $(libhx509_la_SOURCES) || rm -f hx509-protos.h + +$(srcdir)/hx509-private.h: + cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p hx509-private.h $(libhx509_la_SOURCES) || rm -f hx509-private.h + +include_HEADERS = hx509.h hx509-protos.h hx509_err.h + +noinst_PROGRAMS = hxtool + +hxtool_SOURCES = hxtool.c + +hxtool_CPPFLAGS = $(INCLUDE_des) +hxtool_LDADD = libhx509.la $(LIB_roken) ../sl/libsl.la $(LIB_des) +hxtool_LDFLAGS = -pthread + +EXTRA_DIST = hx509_err.et + +CLEANFILES = hx509_err.c hx509_err.h diff --git a/lib/hx509/cert.c b/lib/hx509/cert.c new file mode 100644 index 000000000..64fcf480a --- /dev/null +++ b/lib/hx509/cert.c @@ -0,0 +1,1232 @@ +/* + * Copyright (c) 2004 - 2005 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" +RCSID("$ID$"); + + +struct hx509_verify_ctx_data { + hx509_certs trust_anchors; + int flags; +#define HX509_VERIFY_CTX_F_TIME_SET 1 + time_t time_now; + int max_depth; +#define HX509_VERIFY_MAX_DEPTH 30 +}; + +struct _hx509_cert_attrs { + size_t len; + hx509_cert_attribute *val; +}; + +struct hx509_cert_data { + unsigned int ref; + char *friendlyname; + Certificate *data; + hx509_private_key private_key; + struct _hx509_cert_attrs attrs; +}; + +typedef struct hx509_name_constraints { + /* NameConstraints nc; */ + struct { + GeneralSubtrees *permittedSubtrees; + GeneralSubtrees *excludedSubtrees; + } nc; +} hx509_name_constraints; + +#define GeneralSubtrees_SET(g,var) \ + (g)->len = (var)->len, (g)->val = (var)->val; + + + +Certificate * +_hx509_get_cert(hx509_cert cert) +{ + return cert->data; +} + +int +_hx509_cert_get_version(const Certificate *t) +{ + return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1; +} + +int +hx509_cert_init(const Certificate *c, hx509_cert *cert) +{ + int ret; + + *cert = malloc(sizeof(**cert)); + if (*cert == NULL) + return ENOMEM; + (*cert)->ref = 1; + (*cert)->friendlyname = NULL; + (*cert)->attrs.len = 0; + (*cert)->attrs.val = NULL; + (*cert)->private_key = NULL; + + (*cert)->data = malloc(sizeof(*(*cert)->data)); + if ((*cert)->data == NULL) { + free(*cert); + return ENOMEM; + } + memset((*cert)->data, 0, sizeof(*(*cert)->data)); + ret = copy_Certificate(c, (*cert)->data); + if (ret) { + free((*cert)->data); + free(*cert); + } + return ret; +} + +int +_hx509_cert_assign_private_key_file(hx509_cert cert, + hx509_lock lock, + const char *fn) +{ + int ret; + if (cert->private_key == NULL) { + ret = _hx509_new_private_key(&cert->private_key); + if (ret) + return ret; + } + ret = _hx509_private_key_assign_key_file(cert->private_key, lock, fn); + if (ret) + _hx509_free_private_key(&cert->private_key); + return ret; +} + +/* Doesn't make a copy of `private_key'. */ + +int +_hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key) +{ + if (cert->private_key) + _hx509_free_private_key(&cert->private_key); + cert->private_key = private_key; + return 0; +} + +void +hx509_cert_free(hx509_cert cert) +{ + int i; + + if (cert->ref <= 0) + abort(); + if (--cert->ref > 0) + return; + free_Certificate(cert->data); + free(cert->data); + + for (i = 0; i < cert->attrs.len; i++) { + free_octet_string(&cert->attrs.val[i]->data); + free_oid(&cert->attrs.val[i]->oid); + free(cert->attrs.val[i]); + } + free(cert->attrs.val); + free(cert->friendlyname); + memset(cert, 0, sizeof(cert)); + free(cert); +} + +hx509_cert +hx509_cert_ref(hx509_cert cert) +{ + if (cert->ref <= 0) + abort(); + cert->ref++; + if (cert->ref == 0) + abort(); + return cert; +} + +int +hx509_verify_init_ctx(hx509_verify_ctx *ctx) +{ + hx509_verify_ctx c; + + c = calloc(1, sizeof(*c)); + if (c == NULL) + return ENOMEM; + + c->max_depth = HX509_VERIFY_MAX_DEPTH; + + *ctx = c; + + return 0; +} + +int +hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set) +{ + ctx->trust_anchors = set; + return 0; +} + +void +hx509_verify_set_time(hx509_verify_ctx ctx, time_t t) +{ + ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET; + ctx->time_now = t; +} + +static const Extension * +find_extension(const Certificate *cert, const heim_oid *oid, int *idx) +{ + const TBSCertificate *c = &cert->tbsCertificate; + + if (c->version == NULL || *c->version < 2 || c->extensions == NULL) + return NULL; + + for (;*idx < c->extensions->len; (*idx)++) { + if (heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0) + return &c->extensions->val[*idx]; + } + return NULL; +} + +static int +find_extension_auth_key_id(const Certificate *subject, + AuthorityKeyIdentifier *ai) +{ + const Extension *e; + size_t size; + int i = 0; + + memset(ai, 0, sizeof(*ai)); + + e = find_extension(subject, oid_id_x509_ce_authorityKeyIdentifier(), &i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + return decode_AuthorityKeyIdentifier(e->extnValue.data, + e->extnValue.length, + ai, &size); +} + +static int +find_extension_subject_key_id(const Certificate *issuer, + SubjectKeyIdentifier *si) +{ + const Extension *e; + size_t size; + int i = 0; + + memset(si, 0, sizeof(*si)); + + e = find_extension(issuer, oid_id_x509_ce_subjectKeyIdentifier(), &i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + return decode_SubjectKeyIdentifier(e->extnValue.data, + e->extnValue.length, + si, &size); +} + +static int +find_extension_name_constraints(const Certificate *subject, + NameConstraints *nc) +{ + const Extension *e; + size_t size; + int i = 0; + + memset(nc, 0, sizeof(*nc)); + + e = find_extension(subject, oid_id_x509_ce_nameConstraints(), &i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + return decode_NameConstraints(e->extnValue.data, + e->extnValue.length, + nc, &size); +} + +static int +find_extension_subject_alt_name(const Certificate *cert, int *i, + GeneralNames *sa) +{ + const Extension *e; + size_t size; + + memset(sa, 0, sizeof(*sa)); + + e = find_extension(cert, oid_id_x509_ce_subjectAltName(), i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + return decode_GeneralNames(e->extnValue.data, + e->extnValue.length, + sa, &size); +} + + +static int +check_key_usage(const Certificate *cert, unsigned flags) +{ + const Extension *e; + KeyUsage ku; + size_t size; + int ret, i = 0; + unsigned ku_flags; + + if (_hx509_cert_get_version(cert) < 3) + return 0; + + e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size); + if (ret) + return ret; + ku_flags = KeyUsage2int(ku); + if ((ku_flags & flags) != flags) + return 1; + return 0; +} + +static int +check_basic_constraints(const Certificate *cert, int ca, int depth) +{ + BasicConstraints bc; + const Extension *e; + size_t size; + int ret, i = 0; + + if (_hx509_cert_get_version(cert) < 3) + return 0; + + e = find_extension(cert, oid_id_x509_ce_basicConstraints(), &i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + ret = decode_BasicConstraints(e->extnValue.data, + e->extnValue.length, &bc, + &size); + if (ret) + return ret; + if (ca && (bc.cA == NULL || !*bc.cA)) + ret = HX509_PARENT_NOT_CA; + if (bc.pathLenConstraint) + if (depth - 1 > *bc.pathLenConstraint) + ret = HX509_CA_PATH_TOO_DEEP; + free_BasicConstraints(&bc); + return ret; +} + +int +_hx509_cert_is_parent_cmp(const Certificate *subject, + const Certificate *issuer, + int allow_self_signed) +{ + int diff; + AuthorityKeyIdentifier ai; + SubjectKeyIdentifier si; + int ret_ai, ret_si; + + diff = _hx509_name_cmp(&issuer->tbsCertificate.subject, + &subject->tbsCertificate.issuer); + if (diff) + return diff; + + memset(&ai, 0, sizeof(ai)); + memset(&si, 0, sizeof(si)); + + /* + * Try to find AuthorityKeyIdentifier, if its not present in the + * subject certificate nor the parent. + */ + + ret_ai = find_extension_auth_key_id(subject, &ai); + if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND) + return 1; + ret_si = find_extension_subject_key_id(issuer, &si); + if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND) + return -1; + + if (ret_si && ret_ai) + goto out; + if (ret_ai) + goto out; + if (ret_si) { + if (allow_self_signed) + diff = 0; + else + diff = -1; + goto out; + } + + if (ai.keyIdentifier == NULL) /* XXX */ + diff = -1; + else + diff = heim_octet_string_cmp(ai.keyIdentifier, &si); + if (diff) + goto out; + + out: + free_AuthorityKeyIdentifier(&ai); + free_SubjectKeyIdentifier(&si); + return diff; +} + +static int +certificate_is_anchor(hx509_verify_ctx ctx, const hx509_cert cert) +{ + hx509_query q; + hx509_cert c; + int ret; + + _hx509_query_clear(&q); + + q.match = HX509_QUERY_MATCH_CERTIFICATE; + q.certificate = _hx509_get_cert(cert); + + ret = _hx509_certs_find(ctx->trust_anchors, &q, &c); + if (ret == 0) + hx509_cert_free(c); + return ret == 0; +} + +static int +certificate_is_self_signed(const Certificate *cert) +{ + return _hx509_cert_is_parent_cmp(cert, cert, 1) == 0; +} + +static hx509_cert +find_parent(hx509_verify_ctx ctx, + hx509_path *path, + hx509_certs chain, + hx509_cert current) +{ + hx509_query q; + hx509_cert c; + int ret; + + _hx509_query_clear(&q); + + q.match = HX509_QUERY_FIND_ISSUER_CERT | HX509_QUERY_NO_MATCH_PATH; + q.subject = _hx509_get_cert(current); + q.path = path; + + ret = _hx509_certs_find(chain, &q, &c); + if (ret == 0) + return c; + ret = _hx509_certs_find(ctx->trust_anchors, &q, &c); + if (ret == 0) + return c; + return NULL; +} + +/* + * Path operations are like MEMORY based keyset, but with exposed + * internal so we can do easy searches. + */ + +static int +path_append(hx509_path *path, hx509_cert cert) +{ + hx509_cert *val; + val = realloc(path->val, (path->len + 1) * sizeof(path->val[0])); + if (val == NULL) + return ENOMEM; + + path->val = val; + path->val[path->len] = hx509_cert_ref(cert); + path->len++; + + return 0; +} + +static void +path_free(hx509_path *path) +{ + unsigned i; + + for (i = 0; i < path->len; i++) + hx509_cert_free(path->val[i]); + free(path->val); +} + +/* + * Find path by looking up issuer for the top certificate and continue + * until an anchor certificate is found. A certificate never included + * twice in the path. + * + * The path includes a path from the top certificate to the anchor + * certificate. + */ + +static int +calculate_path(hx509_verify_ctx ctx, + hx509_cert cert, + hx509_certs chain, + hx509_path *path) +{ + hx509_cert parent, current; + int ret; + + ret = path_append(path, cert); + if (ret) + return ret; + + current = hx509_cert_ref(cert); + + while (!certificate_is_anchor(ctx, current)) { + + parent = find_parent(ctx, path, chain, current); + hx509_cert_free(current); + if (parent == NULL) + return HX509_ISSUER_NOT_FOUND; + + ret = path_append(path, parent); + if (ret) + return ret; + current = parent; + + if (path->len > ctx->max_depth) + return HX509_PATH_TOO_LONG; + } + hx509_cert_free(current); + return 0; +} + +static int +AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p, + const AlgorithmIdentifier *q) +{ + int diff; + diff = heim_oid_cmp(&p->algorithm, &q->algorithm); + if (diff) + return diff; + if (p->parameters) { + if (q->parameters) + return heim_any_cmp(p->parameters, + q->parameters); + else + return 1; + } else { + if (q->parameters) + return -1; + else + return 0; + } +} + +int +_hx509_Certificate_cmp(const Certificate *p, const Certificate *q) +{ + int diff; + diff = heim_bit_string_cmp(&p->signatureValue, &q->signatureValue); + if (diff) + return diff; + diff = AlgorithmIdentifier_cmp(&p->signatureAlgorithm, + &q->signatureAlgorithm); + if (diff) + return diff; + diff = heim_octet_string_cmp(&p->tbsCertificate._save, + &q->tbsCertificate._save); + return diff; +} + +int +hx509_cert_cmp(hx509_cert p, hx509_cert q) +{ + return _hx509_Certificate_cmp(p->data, q->data); +} + +int +hx509_cert_issuer(hx509_cert p, hx509_name *name) +{ + return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name); +} + +int +hx509_cert_subject(hx509_cert p, hx509_name *name) +{ + return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name); +} + +int +hx509_cert_serialnumber(hx509_cert p, heim_integer *i) +{ + return copy_heim_integer(&p->data->tbsCertificate.serialNumber, i); +} + +hx509_private_key +_hx509_cert_private_key(hx509_cert p) +{ + return p->private_key; +} + +int +_hx509_cert_private_decrypt(const heim_octet_string *ciphertext, + const heim_oid *encryption_oid, + hx509_cert p, + heim_octet_string *cleartext) +{ + cleartext->data = NULL; + cleartext->length = 0; + + if (p->private_key == NULL) + return EINVAL; + + return _hx509_private_key_private_decrypt(ciphertext, + encryption_oid, + p->private_key, + cleartext); +} + +int +_hx509_cert_public_encrypt(const heim_octet_string *cleartext, + const hx509_cert p, + heim_oid *encryption_oid, + heim_octet_string *ciphertext) +{ + return _hx509_public_encrypt(cleartext, p->data, + encryption_oid, ciphertext); +} + +int +_hx509_cert_private_sigature(const heim_octet_string *cleartext, + const heim_oid *signature_oid, + hx509_cert p, + heim_octet_string *signature) +{ + memset(signature, 0, sizeof(*signature)); + return 0; +} + + +/* + * + */ + +time_t +_hx509_Time2time_t(const Time *t) +{ + switch(t->element) { + case choice_Time_utcTime: + return t->u.utcTime; + case choice_Time_generalTime: + return t->u.generalTime; + } + return 0; +} + +/* + * + */ + +static int +init_name_constraints(hx509_name_constraints *nc) +{ + memset(nc, 0, sizeof(*nc)); + + nc->nc.permittedSubtrees = calloc(1, sizeof(*nc->nc.permittedSubtrees)); + if (nc->nc.permittedSubtrees == NULL) + return ENOMEM; + nc->nc.excludedSubtrees = calloc(1, sizeof(*nc->nc.excludedSubtrees)); + if (nc->nc.excludedSubtrees == NULL) { + free(nc->nc.permittedSubtrees); + nc->nc.permittedSubtrees = NULL; + return ENOMEM; + } + return 0; +} + +static int +append_tree(const GeneralSubtrees *add, GeneralSubtrees *merge) +{ + unsigned int num, i; + GeneralSubtree *st; + int ret; + + num = merge->len + add->len; + if (num < merge->len) + return HX509_RANGE; + if (num > UINT_MAX/sizeof(merge->val[0])) + return HX509_RANGE; + st = realloc(merge->val, sizeof(*st) * num); + if (st == NULL) + return ENOMEM; + merge->val = st; + memset(&st[merge->len], 0, sizeof(add->val[0]) * add->len); + for (i = 0; i < add->len; i++) { + ret = copy_GeneralSubtree(&add->val[i], + &merge->val[merge->len + i]); + if (ret) + return ret; + } + merge->len = num; + + return 0; +} + +static int +add_name_constraints(const Certificate *c, int not_ca, + hx509_name_constraints *nc) +{ + NameConstraints tnc; + int ret; + + ret = find_extension_name_constraints(c, &tnc); + if (ret == HX509_EXTENSION_NOT_FOUND) + return 0; + else if (ret) + return ret; + else if (not_ca) { + ret = HX509_VERIFY_CONSTRAINTS; + } else { + GeneralSubtrees gs; + if (tnc.permittedSubtrees) { + GeneralSubtrees_SET(&gs, tnc.permittedSubtrees); + ret = append_tree(&gs, nc->nc.permittedSubtrees); + } + if (ret == 0 && tnc.excludedSubtrees) { + GeneralSubtrees_SET(&gs, tnc.excludedSubtrees); + ret = append_tree(&gs, nc->nc.excludedSubtrees); + } + } + free_NameConstraints(&tnc); + return ret; +} + +static int +match_RDN(const RelativeDistinguishedName *c, + const RelativeDistinguishedName *n) +{ + int i; + + if (c->len != n->len) + return HX509_NAME_CONSTRAINT_ERROR; + + for (i = 0; i < n->len; i++) { + if (heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + if (_hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + } + return 0; +} + +static int +match_X501Name(const Name *c, const Name *n) +{ + int i, j, ret; + + if (c->element != choice_Name_rdnSequence + || n->element != choice_Name_rdnSequence) + return 0; + if (c->u.rdnSequence.len > n->u.rdnSequence.len) + return HX509_NAME_CONSTRAINT_ERROR; + for (i = c->u.rdnSequence.len - 1, j = n->u.rdnSequence.len - 1; + i >= 0; i--, j--) { + ret = match_RDN(&c->u.rdnSequence.val[i], &c->u.rdnSequence.val[j]); + if (ret) + return ret; + } + return 0; +} + + +static int +match_general_name(const GeneralName *c, const GeneralName *n) +{ + if (c->element != n->element) + return 0; + + switch(c->element) { + case choice_GeneralName_otherName: + if (heim_oid_cmp(&c->u.otherName.type_id, + &n->u.otherName.type_id) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + if (heim_any_cmp(&c->u.otherName.value, + &n->u.otherName.value) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + return 0; + case choice_GeneralName_rfc822Name: { + const char *s; + size_t len1, len2; + s = strchr(c->u.rfc822Name, '@'); + if (s) { + if (strcasecmp(c->u.rfc822Name, n->u.rfc822Name) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + } else { + s = strchr(n->u.rfc822Name, '@'); + if (s == NULL) + return HX509_NAME_CONSTRAINT_ERROR; + len1 = strlen(c->u.rfc822Name); + len2 = strlen(s + 1); + if (len1 > len2) + return HX509_NAME_CONSTRAINT_ERROR; + if (strcasecmp(s + 1 + len2 - len1, c->u.rfc822Name) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + if (len1 < len2 && s[len2 - len1] != '.') + return HX509_NAME_CONSTRAINT_ERROR; + } + return 0; + } + case choice_GeneralName_dNSName: { + size_t len1, len2; + + len1 = strlen(c->u.dNSName); + len2 = strlen(n->u.dNSName); + if (len1 > len2) + return HX509_NAME_CONSTRAINT_ERROR; + if (strcasecmp(&n->u.dNSName[len2 - len1], c->u.dNSName) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + return 0; + } + case choice_GeneralName_directoryName: { + Name c_name, n_name; + c_name._save.data = NULL; + c_name._save.length = 0; + c_name.element = c->u.directoryName.element; + c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence; + + n_name._save.data = NULL; + n_name._save.length = 0; + n_name.element = n->u.directoryName.element; + n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence; + + return match_X501Name(&c_name, &n_name); + } + case choice_GeneralName_uniformResourceIdentifier: + case choice_GeneralName_iPAddress: + case choice_GeneralName_registeredID: + default: + return HX509_NAME_CONSTRAINT_ERROR; + } +} + + +static int +match_name(const GeneralName *n, const Certificate *c) +{ + GeneralName certname; + GeneralNames sa; + int ret, i, j; + + certname.element = choice_GeneralName_directoryName; + /* certname.u.directoryName = c->tbsCertificate.subject; */ + + certname.u.directoryName.element = c->tbsCertificate.subject.element; + certname.u.directoryName.u.rdnSequence = + c->tbsCertificate.subject.u.rdnSequence; + + ret = match_general_name(n, &certname); + if (ret) + return ret; + + i = 0; + do { + ret = find_extension_subject_alt_name(c, &i, &sa); + if (ret == HX509_EXTENSION_NOT_FOUND) { + ret = 0; + break; + } else if (ret != 0) + break; + + for (j = 0; j < sa.len; j++) { + ret = match_general_name(n, &sa.val[j]); + if (ret) + break; + } + free_GeneralNames(&sa); + } while (ret == 0); + + return ret; +} + +static int +match_tree(const GeneralSubtrees *t, const Certificate *c, int *match) +{ + unsigned int i; + *match = 0; + for (i = 0; i < t->len; i++) { + if (t->val[i].minimum && t->val[i].maximum) + return HX509_RANGE; + if (match_name(&t->val[i].base, c)) + *match = 1; + } + return 0; +} + +static int +check_name_constraints(const hx509_name_constraints *nc, + const Certificate *c) +{ + GeneralSubtrees gs; + int match, ret; + + if (nc->nc.permittedSubtrees->len > 0) { + GeneralSubtrees_SET(&gs, nc->nc.permittedSubtrees); + + ret = match_tree(&gs, c, &match); + if (ret) + return ret; + if (match == 0) + return HX509_VERIFY_CONSTRAINTS; + } + if (nc->nc.excludedSubtrees->len > 0) { + GeneralSubtrees_SET(&gs, nc->nc.excludedSubtrees); + + ret = match_tree(&gs, c, &match); + if (ret) + return ret; + if (match) + return HX509_VERIFY_CONSTRAINTS; + } + return 0; +} + +static void +free_name_constraints(hx509_name_constraints *nc) +{ + /* free_NameConstraints(&nc->nc); */ + if (nc->nc.permittedSubtrees) { + free_GeneralSubtrees(nc->nc.permittedSubtrees); + free(nc->nc.permittedSubtrees); + nc->nc.permittedSubtrees = NULL; + } + if (nc->nc.excludedSubtrees) { + free_GeneralSubtrees(nc->nc.excludedSubtrees); + free(nc->nc.excludedSubtrees); + nc->nc.excludedSubtrees = NULL; + } +} + +int +hx509_verify_path(hx509_verify_ctx ctx, hx509_cert cert, hx509_certs chain) +{ + hx509_name_constraints nc; + hx509_path path; +#if 0 + const AlgorithmIdentifier *alg_id; +#endif + int ret, i; + + ret = init_name_constraints(&nc); + if (ret) + return ret; + + path.val = NULL; + path.len = 0; + + if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0) + ctx->time_now = time(NULL); + + /* + * Calculate the path from the certificate user presented to the + * to an anchor. + */ + ret = calculate_path(ctx, cert, chain, &path); + if (ret) + goto out; + +#if 0 + alg_id = path.val[path->len - 1]->data->tbsCertificate.signature; +#endif + + /* + * Verify constraints, do this backward so path constraints are + * checked in the right order. + */ + + for (ret = 0, i = path.len - 1; i >= 0; i--) { + Certificate *c; + c = path.val[i]->data; + +#if 0 + /* check that algorithm and parameters is the same */ + /* XXX this is probably wrong */ + ret = alg_cmp(&c->tbsCertificate.signature, alg_id); + if (ret) { + ret = HX509_PATH_ALGORITHM_CHANGED; + goto out; + } +#endif + + /* + * Lets do some basic check on issuer like + * keyUsage.keyCertSign and basicConstraints.cA bit. + */ + if (i != 0) { + if (check_key_usage(c, 1 << 5)) { /* XXX make constants */ + ret = ENOENT; + goto out; + } + if (check_basic_constraints(c, 1, path.len - i - 1)) { + ret = ENOENT; + goto out; + } + } + + { + time_t t; + + t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore); + if (t > ctx->time_now) { + ret = HX509_CERT_USED_BEFORE_TIME; + goto out; + } + t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter); + if (t < ctx->time_now) { + ret = HX509_CERT_USED_AFTER_TIME; + goto out; + } + } + + /* verify name constraints, not for selfsigned and anchor */ + if (!certificate_is_self_signed(c) || i == path.len - 1) { + ret = check_name_constraints(&nc, c); + if (ret) + goto out; + } + ret = add_name_constraints(c, i == 0, &nc); + if (ret) + goto out; + + /* XXX verify all other silly constraints */ + } + + /* + * Verify constraints, do this backward so public key working + * parameter is passed up from the anchor up though the chain. + */ + + for (i = path.len - 1; i >= 0; i--) { + Certificate *signer, *c; + heim_octet_string os; + + c = path.val[i]->data; + /* is last in chain and thus the self-signed */ + signer = path.val[i == path.len - 1 ? i : i + 1]->data; + + if (c->signatureValue.length & 7) { + ret = EINVAL; + break; + } + os.data = c->signatureValue.data; + os.length = c->signatureValue.length / 8; + + /* verify signatureValue */ + ret = _hx509_verify_signature(signer, + &c->signatureAlgorithm, + &c->tbsCertificate._save, + &os); + if (ret) { + break; + } + } + + out: + free_name_constraints(&nc); + path_free(&path); + + return ret; +} + +int +hx509_verify_signature(const hx509_cert signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + return _hx509_verify_signature(signer->data, alg, data, sig); +} + +int +_hx509_set_cert_attribute(hx509_cert cert, const heim_oid *oid, + const heim_octet_string *attr) +{ + hx509_cert_attribute a; + void *d; + + if (hx509_cert_get_attribute(cert, oid) != NULL) + return 0; + + d = realloc(cert->attrs.val, + sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1)); + if (d == NULL) + return ENOMEM; + cert->attrs.val = d; + + a = malloc(sizeof(*a)); + if (a == NULL) + return ENOMEM; + + copy_octet_string(attr, &a->data); + copy_oid(oid, &a->oid); + + cert->attrs.val[cert->attrs.len] = a; + cert->attrs.len++; + + return 0; +} + +const hx509_cert_attribute +hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid) +{ + int i; + for (i = 0; i < cert->attrs.len; i++) + if (heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0) + return cert->attrs.val[i]; + return NULL; +} + +int +hx509_cert_set_friendly_name(hx509_cert cert, const char *name) +{ + if (cert->friendlyname) + free(cert->friendlyname); + cert->friendlyname = strdup(name); + if (cert->friendlyname == NULL) + return ENOMEM; + return 0; +} + + +const char * +hx509_cert_get_friendly_name(hx509_cert cert) +{ + hx509_cert_attribute a; + PKCS9_friendlyName n; + size_t sz; + int ret, i; + + if (cert->friendlyname) + return cert->friendlyname; + + a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_friendlyName()); + if (a == NULL) { + /* XXX use subject name ? */ + return NULL; + } + + ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz); + if (ret) + return NULL; + + if (n.len != 1) { + free_PKCS9_friendlyName(&n); + return NULL; + } + + cert->friendlyname = malloc(n.val[0].length + 1); + if (cert->friendlyname == NULL) { + free_PKCS9_friendlyName(&n); + return NULL; + } + + for (i = 0; i < n.val[0].length; i++) { + if (n.val[0].data[i] <= 0xff) + cert->friendlyname[i] = n.val[0].data[i] & 0xff; + else + cert->friendlyname[i] = 'X'; + } + cert->friendlyname[i] = '\0'; + free_PKCS9_friendlyName(&n); + + return cert->friendlyname; +} + +void +_hx509_query_clear(hx509_query *q) +{ + memset(q, 0, sizeof(*q)); +} + +int +_hx509_query_match_cert(const hx509_query *q, hx509_cert cert) +{ + Certificate *c = _hx509_get_cert(cert); + + if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) && + _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0) + return 0; + + if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) && + _hx509_Certificate_cmp(q->certificate, c) != 0) + return 0; + + if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER) + && heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0) + return 0; + + if ((q->match & HX509_QUERY_MATCH_ISSUER_NAME) + && _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name) != 0) + return 0; + + if ((q->match & HX509_QUERY_MATCH_SUBJECT_NAME) + && _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name) != 0) + return 0; + + if ((q->match & HX509_QUERY_MATCH_SUBJECT_ID)) + return 0; + if ((q->match & HX509_QUERY_MATCH_ISSUER_ID)) + return 0; + if ((q->match & HX509_QUERY_PRIVATE_KEY) + && _hx509_cert_private_key(cert) == NULL) + return 0; + + if ((q->match & HX509_QUERY_ANCHOR)) + return 0; + + if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) { + hx509_cert_attribute a; + + a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_localKeyId()); + if (a == NULL) + return 0; + if (heim_octet_string_cmp(&a->data, q->local_key_id) != 0) + return 0; + } + + if (q->match & HX509_QUERY_NO_MATCH_PATH) { + size_t i; + + for (i = 0; i < q->path->len; i++) + if (hx509_cert_cmp(q->path->val[i], cert) == 0) + return 0; + } + + if (q->match & ~HX509_QUERY_MASK) + return 0; + + return 1; +} diff --git a/lib/hx509/cms.c b/lib/hx509/cms.c new file mode 100644 index 000000000..5b7719768 --- /dev/null +++ b/lib/hx509/cms.c @@ -0,0 +1,1010 @@ +/* + * Copyright (c) 2003 - 2005 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" +# +RCSID("$Id$"); + +#define ALLOC(X, N) (X) = calloc((N), sizeof(*(X))) +#define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0) + +int +hx509_cms_wrap_ContentInfo(const heim_oid *oid, + const heim_octet_string *buf, + ContentInfo *content_info) +{ + int ret; + + ret = copy_oid(oid, &content_info->contentType); + if (ret) + return ret; + ALLOC(content_info->content, 1); + if (content_info->content == NULL) + return ENOMEM; + content_info->content->data = malloc(buf->length); + if (content_info->content->data == NULL) + return ENOMEM; + memcpy(content_info->content->data, buf->data, buf->length); + content_info->content->length = buf->length; + return 0; +} + +static int +fill_CMSIdentifier(const hx509_cert cert, CMSIdentifier *id) +{ + hx509_name name; + int ret; + + id->element = choice_CMSIdentifier_issuerAndSerialNumber; + ret = hx509_cert_issuer(cert, &name); + if (ret) + return ret; + ret = copy_Name(&name->der_name, + &id->u.issuerAndSerialNumber.issuer); + hx509_name_free(&name); + if (ret) + return ret; + + ret = hx509_cert_serialnumber(cert, + &id->u.issuerAndSerialNumber.serialNumber); + return ret; +} + +static int +find_CMSIdentifier(CMSIdentifier *client, + hx509_certs certs, + hx509_cert *signer_cert, + int match) +{ + hx509_query q; + hx509_cert cert; + Certificate c; + int ret; + + memset(&c, 0, sizeof(c)); + _hx509_query_clear(&q); + + *signer_cert = NULL; + + switch (client->element) { + case choice_CMSIdentifier_issuerAndSerialNumber: + q.serial = &client->u.issuerAndSerialNumber.serialNumber; + q.issuer_name = &client->u.issuerAndSerialNumber.issuer; + q.match = HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME; + break; + case choice_CMSIdentifier_subjectKeyIdentifier: + default: + return HX509_CMS_NO_RECIPIENT_CERTIFICATE; + } + + q.match |= match; + + ret = _hx509_certs_find(certs, &q, &cert); + if (ret) + return ret; + + *signer_cert = cert; + + return 0; +} + +int +hx509_cms_unenvelope(hx509_certs certs, + const void *data, + size_t length, + heim_oid *contentType, + heim_octet_string *content) +{ + heim_octet_string key; + EnvelopedData ed; + KeyTransRecipientInfo *ri; + hx509_cert cert; + AlgorithmIdentifier *ai; + heim_octet_string *enccontent; + heim_octet_string *params, params_data; + size_t size; + int ret, i; + + + memset(&key, 0, sizeof(key)); + memset(&ed, 0, sizeof(ed)); + memset(content, 0, sizeof(*content)); + memset(contentType, 0, sizeof(*contentType)); + + ret = decode_EnvelopedData(data, length, &ed, &size); + if (ret) + return ret; + + /* XXX check content of ed */ + + if (ed.encryptedContentInfo.encryptedContent == NULL) { + ret = HX509_CMS_NO_DATA_AVAILABLE; + goto out; + } + + cert = NULL; + ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE; + for (i = 0; i < ed.recipientInfos.len; i++) { + ri = &ed.recipientInfos.val[i]; + + /* ret = search_keyset(ri, + * PRIVATE_KEY, + * ki->keyEncryptionAlgorithm.algorithm); + */ + + ret = find_CMSIdentifier(&ri->rid, certs, &cert, + HX509_QUERY_PRIVATE_KEY); + if (ret) { + ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE; + continue; + } + + ret = _hx509_cert_private_decrypt(&ri->encryptedKey, + &ri->keyEncryptionAlgorithm.algorithm, + cert, &key); + + hx509_cert_free(cert); + if (ret == 0) + break; + cert = NULL; + } + + if (cert == NULL) + goto out; + + ret = copy_oid(&ed.encryptedContentInfo.contentType, contentType); + if (ret) + goto out; + + enccontent = ed.encryptedContentInfo.encryptedContent; + + ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm; + if (ai->parameters) { + params_data.data = ai->parameters->data; + params_data.length = ai->parameters->length; + params = ¶ms_data; + } else + params = NULL; + + { + hx509_crypto crypto; + heim_octet_string *ivec = NULL, ivec_data; + + ret = hx509_crypto_init(NULL, &ai->algorithm, &crypto); + if (ret) + goto out; + + ret = hx509_crypto_set_key_data(crypto, key.data, key.length); + if (ret) + goto out; + + if (params) { + ret = hx509_crypto_set_params(crypto, params, &ivec_data); + ivec = &ivec_data; + } + + ret = hx509_crypto_decrypt(crypto, + enccontent->data, + enccontent->length, + ivec, + content); + if (ivec) + free_octet_string(&ivec_data); + } + + out: + + free_octet_string(&key); + if (ret) { + free_oid(contentType); + free_octet_string(content); + } + + return ret; +} + +int +hx509_cms_envelope_1(hx509_cert cert, + const void *data, + size_t length, + const heim_oid *encryption_type, + const heim_oid *contentType, + heim_octet_string *content) +{ + KeyTransRecipientInfo *ri; + EnvelopedData ed; + heim_octet_string ivec; + heim_octet_string key; + int ret; + size_t size; + + memset(&ivec, 0, sizeof(ivec)); + memset(&key, 0, sizeof(key)); + memset(&ed, 0, sizeof(ed)); + memset(content, 0, sizeof(*content)); + + if (encryption_type == NULL) + encryption_type = oid_id_aes_256_cbc(); + + hx509_crypto crypto; + + ret = hx509_crypto_init(NULL, encryption_type, &crypto); + if (ret) + goto out; + + ret = hx509_crypto_set_random_key(crypto, &key); + if (ret) { + hx509_crypto_destroy(crypto); + goto out; + } + + ret = hx509_crypto_encrypt(crypto, + data, + length, + &ivec, + &ed.encryptedContentInfo.encryptedContent); + if (ret) { + hx509_crypto_destroy(crypto); + goto out; + } + + { + AlgorithmIdentifier *enc_alg; + enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm; + ret = copy_oid(encryption_type, &enc_alg->algorithm); + if (ret) + goto out; + + ALLOC(enc_alg->parameters, 1); + if (enc_alg->parameters == NULL) { + ret = ENOMEM; + goto out; + } + + ret = hx509_crypto_get_params(crypto, + &ivec, + enc_alg->parameters); + } + hx509_crypto_destroy(crypto); + if (ret) + goto out; + + ALLOC_SEQ(&ed.recipientInfos, 1); + if (ed.recipientInfos.val == NULL) { + ret = ENOMEM; + goto out; + } + + ri = &ed.recipientInfos.val[0]; + + ri->version = 0; + ret = fill_CMSIdentifier(cert, &ri->rid); + if (ret) + goto out; + + ret = _hx509_cert_public_encrypt(&key, cert, + &ri->keyEncryptionAlgorithm.algorithm, + &ri->encryptedKey); + if (ret) + goto out; + + /* + * + */ + + ed.version = 0; + ed.originatorInfo = NULL; + + ret = copy_oid(contentType, &ed.encryptedContentInfo.contentType); + if (ret) + goto out; + + ed.unprotectedAttrs = NULL; + + ASN1_MALLOC_ENCODE(EnvelopedData, content->data, content->length, + &ed, &size, ret); + if (ret) + goto out; + out: + if (ret) { + free_octet_string(content); + } + free_octet_string(&key); + free_octet_string(&ivec); + free_EnvelopedData(&ed); + + return ret; +} + +static int +any_to_certs(const SignedData *sd, hx509_certs certs) +{ + int ret, i; + + if (sd->certificates == NULL) + return 0; + + for (i = 0; i < sd->certificates->len; i++) { + Certificate cert; + hx509_cert c; + + const void *p = sd->certificates->val[i].data; + size_t size, length = sd->certificates->val[i].length; + + ret = decode_Certificate(p, length, &cert, &size); + if (ret) + return ret; + + ret = hx509_cert_init(&cert, &c); + free_Certificate(&cert); + if (ret) + return ret; + ret = hx509_certs_add(certs, c); + if (ret) { + hx509_cert_free(c); + return ret; + } + } + + return 0; +} + +static const Attribute * +find_attribute(const CMSAttributes *attr, const heim_oid *oid) +{ + int i; + for (i = 0; i < attr->len; i++) + if (heim_oid_cmp(&attr->val[i].type, oid) == 0) + return &attr->val[i]; + return NULL; +} + +int +hx509_cms_verify_signed(hx509_verify_ctx ctx, + const char *data, + size_t length, + heim_oid *contentType, + heim_octet_string *content, + hx509_certs *signer_certs) +{ + SignerInfo *signer_info; + hx509_cert cert = NULL; + hx509_certs certs = NULL; + SignedData sd; + size_t size; + int ret, i, found_valid_sig; + + *signer_certs = NULL; + content->data = NULL; + content->length = 0; + contentType->length = 0; + contentType->components = NULL; + + memset(&sd, 0, sizeof(sd)); + + ret = decode_SignedData(data, length, &sd, &size); + if (ret) { + goto out; + } + + if (sd.encapContentInfo.eContent == NULL) { + ret = HX509_CMS_NO_DATA_AVAILABLE; + goto out; + } + + ret = hx509_certs_init("MEMORY:cms-cert-buffer", 0, NULL, &certs); + if (ret) + goto out; + + ret = hx509_certs_init("MEMORY:cms-signer-certs", 0, NULL, signer_certs); + if (ret) + goto out; + + /* XXX Check CMS version */ + + ret = any_to_certs(&sd, certs); + if (ret) { + goto out; + } + + ret = HX509_CMS_SIGNER_NOT_FOUND; + for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) { + heim_octet_string *signed_data; + const heim_oid *match_oid; + heim_oid decode_oid; + + signer_info = &sd.signerInfos.val[i]; + match_oid = NULL; + + if (signer_info->signature.length == 0) { + ret = HX509_CMS_MISSING_SIGNER_DATA; + continue; + } + + ret = find_CMSIdentifier(&signer_info->sid, certs, &cert, 0); + if (ret) + continue; + + if (signer_info->signedAttrs) { + const AlgorithmIdentifier *salg; + const Attribute *attr; + + CMSAttributes sa; + heim_octet_string os; + + salg = _hx509_digest_signature(&signer_info->signatureAlgorithm); + if (salg == NULL) { + ret = HX509_ALG_NOT_SUPP; + continue; + } + + sa.val = signer_info->signedAttrs->val; + sa.len = signer_info->signedAttrs->len; + + /* verify that sigature exists */ + attr = find_attribute(&sa, oid_id_pkcs9_messageDigest()); + if (attr == NULL) { + ret = HX509_CRYPTO_SIGNATURE_MISSING; + continue; + } + if (attr->value.len != 1) { + ret = HX509_CRYPTO_SIGNATURE_MISSING; + continue; + } + + ret = decode_MessageDigest(attr->value.val[0].data, + attr->value.val[0].length, + &os, + &size); + if (ret) + continue; + + ret = _hx509_verify_signature(NULL, + salg, + sd.encapContentInfo.eContent, + &os); + free_octet_string(&os); + + /* + * Fetch content oid inside signedAttrs or set it to + * id-pkcs7-data. + */ + attr = find_attribute(&sa, oid_id_pkcs9_contentType()); + if (attr == NULL) { + match_oid = oid_id_pkcs7_data(); + } else { + if (attr->value.len != 1) { + ret = HX509_CMS_DATA_OID_MISMATCH; + continue; + } + ret = decode_ContentType(attr->value.val[0].data, + attr->value.val[0].length, + &decode_oid, + &size); + if (ret) + continue; + match_oid = &decode_oid; + } + + signed_data = calloc(1, sizeof(*signed_data)); + if (signed_data == NULL) { + if (match_oid == &decode_oid) + free_oid(&decode_oid); + ret = ENOMEM; + continue; + } + + ASN1_MALLOC_ENCODE(CMSAttributes, + signed_data->data, + signed_data->length, + &sa, + &size, ret); + if (ret) { + if (match_oid == &decode_oid) + free_oid(&decode_oid); + free(signed_data); + continue; + } + + } else { + signed_data = sd.encapContentInfo.eContent; + match_oid = oid_id_pkcs7_data(); + } + if (ret) + return ret; + + if (heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType)) + ret = HX509_CMS_DATA_OID_MISMATCH; + + if (match_oid == &decode_oid) + free_oid(&decode_oid); + + if (ret == 0) + ret = hx509_verify_signature(cert, + &signer_info->signatureAlgorithm, + signed_data, + &signer_info->signature); + + if (signed_data != sd.encapContentInfo.eContent) { + free_octet_string(signed_data); + free(signed_data); + } + if (ret) { + hx509_cert_free(cert); + continue; + } + + ret = hx509_verify_path(ctx, cert, certs); + if (ret) { + hx509_cert_free(cert); + continue; + } + + ret = hx509_certs_add(*signer_certs, hx509_cert_ref(cert)); + if (ret) { + hx509_cert_free(cert); + continue; + } + found_valid_sig++; + } + if (found_valid_sig == 0) { + return ret; + } + + ret = copy_oid(&sd.encapContentInfo.eContentType, contentType); + if (ret) { + goto out; + } + + content->data = malloc(sd.encapContentInfo.eContent->length); + if (content->data == NULL) { + ret = ENOMEM; + goto out; + } + content->length = sd.encapContentInfo.eContent->length; + memcpy(content->data,sd.encapContentInfo.eContent->data,content->length); + + out: + free_SignedData(&sd); + if (certs) + hx509_certs_free(&certs); + if (ret) { + if (*signer_certs) + hx509_certs_free(signer_certs); + free_oid(contentType); + free_octet_string(content); + } + + return ret; +} + +int +_hx509_set_digest_alg(DigestAlgorithmIdentifier *id, + const heim_oid *oid, + void *param, size_t length) +{ + int ret; + if (param) { + id->parameters = malloc(sizeof(*id->parameters)); + if (id->parameters == NULL) + return ENOMEM; + id->parameters->data = malloc(length); + if (id->parameters->data == NULL) { + free(id->parameters); + id->parameters = NULL; + return ENOMEM; + } + memcpy(id->parameters->data, param, length); + id->parameters->length = length; + } else + id->parameters = NULL; + ret = copy_oid(oid, &id->algorithm); + if (ret) { + if (id->parameters) { + free(id->parameters->data); + free(id->parameters); + id->parameters = NULL; + } + return ret; + } + return 0; +} + +static int +add_one_attribute(Attribute **attr, + unsigned int *len, + const heim_oid *oid, + heim_octet_string *data) +{ + void *d; + int ret; + + d = realloc(*attr, sizeof((*attr)[0]) * (*len + 1)); + if (d == NULL) + return ENOMEM; + (*attr) = d; + + ret = copy_oid(oid, &(*attr)[*len].type); + if (ret) + return ret; + + ALLOC_SEQ(&(*attr)[*len].value, 1); + if ((*attr)[*len].value.val == NULL) { + free_oid(&(*attr)[*len].type); + return ENOMEM; + } + + (*attr)[*len].value.val[0].data = data->data; + (*attr)[*len].value.val[0].length = data->length; + + *len += 1; + + return 0; +} + + + +int +hx509_cms_create_signed_1(const heim_oid *eContentType, + const void *data, size_t length, + const heim_oid *signature_type, + hx509_cert cert, + heim_octet_string *signed_data) +{ + hx509_name name; + SignerInfo *signer_info; + heim_octet_string buf; + SignedData sd; + int ret; + size_t size; + + memset(&sd, 0, sizeof(sd)); + memset(&name, 0, sizeof(name)); + + if (_hx509_cert_private_key(cert) == NULL) + return HX509_PRIVATE_KEY_MISSING; + + /* XXX */ + if (signature_type == NULL) + signature_type = oid_id_secsig_sha_1(); + + + sd.version = 3; + + copy_oid(eContentType, &sd.encapContentInfo.eContentType); + ALLOC(sd.encapContentInfo.eContent, 1); + if (sd.encapContentInfo.eContent == NULL) { + ret = ENOMEM; + goto out; + } + + sd.encapContentInfo.eContent->data = malloc(length); + if (sd.encapContentInfo.eContent->data == NULL) { + ret = ENOMEM; + goto out; + } + memcpy(sd.encapContentInfo.eContent->data, data, length); + sd.encapContentInfo.eContent->length = length; + + ALLOC_SEQ(&sd.signerInfos, 1); + if (sd.signerInfos.val == NULL) { + ret = ENOMEM; + goto out; + } + + signer_info = &sd.signerInfos.val[0]; + + signer_info->version = 1; + + ret = fill_CMSIdentifier(cert, &signer_info->sid); + if (ret) + goto out; + + ret = _hx509_set_digest_alg(&signer_info->digestAlgorithm, + signature_type, "\x05\x00", 2); + if (ret) { + goto out; + } + + signer_info->signedAttrs = NULL; + signer_info->unsignedAttrs = NULL; + + ALLOC(signer_info->signedAttrs, 1); + if (signer_info->signedAttrs == NULL) { + ret = ENOMEM; + goto out; + } + + { + heim_octet_string digest; + + ret = _hx509_create_signature(NULL, + hx509_signature_sha1(), + sd.encapContentInfo.eContent, + NULL, + &digest); + if (ret) + goto out; + + ASN1_MALLOC_ENCODE(MessageDigest, + buf.data, + buf.length, + &digest, + &size, + ret); + free_octet_string(&digest); + if (ret) + goto out; + if (size != buf.length) + abort(); + + ret = add_one_attribute(&signer_info->signedAttrs->val, + &signer_info->signedAttrs->len, + oid_id_pkcs9_messageDigest(), + &buf); + if (ret) + goto out; + + } + + if (heim_oid_cmp(eContentType, oid_id_pkcs7_data()) != 0) { + + ASN1_MALLOC_ENCODE(ContentType, + buf.data, + buf.length, + eContentType, + &size, + ret); + if (ret) + goto out; + if (size != buf.length) + abort(); + + ret = add_one_attribute(&signer_info->signedAttrs->val, + &signer_info->signedAttrs->len, + oid_id_pkcs9_contentType(), + &buf); + if (ret) + goto out; + + } + + + { + CMSAttributes sa; + heim_octet_string os; + + sa.val = signer_info->signedAttrs->val; + sa.len = signer_info->signedAttrs->len; + + ASN1_MALLOC_ENCODE(CMSAttributes, + os.data, + os.length, + &sa, + &size, + ret); + if (ret) + goto out; + if (size != os.length) + abort(); + + + ret = _hx509_create_signature(_hx509_cert_private_key(cert), + hx509_signature_rsa_with_sha1(), + &os, + &signer_info->signatureAlgorithm, + &signer_info->signature); + + free_octet_string(&os); + if (ret) + goto out; + } + + ALLOC_SEQ(&sd.digestAlgorithms, 1); + if (sd.digestAlgorithms.val == NULL) { + ret = ENOMEM; + goto out; + } + + ret = _hx509_set_digest_alg(&sd.digestAlgorithms.val[0], + signature_type, "\x05\x00", 2); + if (ret) { + goto out; + } + + ALLOC(sd.certificates, 1); + if (sd.certificates == NULL) { + ret = ENOMEM; + goto out; + } + ALLOC_SEQ(sd.certificates, 1); + if (sd.certificates->val == NULL) { + ret = ENOMEM; + goto out; + } + + + ASN1_MALLOC_ENCODE(Certificate, + sd.certificates->val[0].data, + sd.certificates->val[0].length, + _hx509_get_cert(cert), + &size, ret); + if (ret) + goto out; + + ASN1_MALLOC_ENCODE(SignedData, + signed_data->data, signed_data->length, + &sd, &size, ret); + if (ret) + goto out; + if (signed_data->length != size) + abort(); + + out: + free_SignedData(&sd); + + return ret; +} + +int +hx509_cms_decrypt_encrypted(hx509_lock lock, + const char *data, + size_t length, + heim_oid *contentType, + heim_octet_string *content) +{ + heim_octet_string cont; + const struct _hx509_password *pw; + CMSEncryptedData ed; + AlgorithmIdentifier *ai; + int ret, i; + + memset(content, 0, sizeof(*content)); + memset(&cont, 0, sizeof(cont)); + + ret = decode_CMSEncryptedData(data, length, &ed, NULL); + if (ret) + return ret; + + if (ed.encryptedContentInfo.encryptedContent == NULL) { + ret = HX509_CMS_NO_DATA_AVAILABLE; + goto out; + } + + ret = copy_oid(&ed.encryptedContentInfo.contentType, contentType); + if (ret) + goto out; + + ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm; + if (ai->parameters == NULL) { + ret = HX509_ALG_NOT_SUPP; + goto out; + } + + pw = _hx509_lock_get_passwords(lock); + + ret = HX509_CRYPTO_INTERNAL_ERROR; + for (i = 0; i < pw->len; i++) { + ret = _hx509_pbe_decrypt(pw->val[i], + ai, + ed.encryptedContentInfo.encryptedContent, + &cont); + if (ret == 0) + break; + } + if (ret) + goto out; + + *content = cont; + + out: + if (ret) { + if (cont.data) + free(cont.data); + } + free_CMSEncryptedData(&ed); + return ret; +} + +#if 0 +static int +_hx509_pkcs12_string2key(unsigned char id, heim_oid *alg, const char *pw, + const heim_octet_string *salt, size_t keysize, + unsigned int iterations, + heim_octet_string *key) +{ + int i; + + if (heim_oid_cmp(alg, oid_id_pbewithSHAAnd40BitRC2_CBC()) != 0) + return EINVAL; + + printf("encryption type: "); + for (i = 0; i < alg->length; i++) + printf("%d%s", alg->components[i], i < alg->length - 1 ? "." : ""); + printf("\n"); + + SHA_CTX hash; + unsigned char pwbuf[128]; + unsigned char B[64]; + size_t pwlen = strlen(pw); + size_t have_bytes = 0; + unsigned char *p, hashout[20]; + + key->data = malloc(keysize); + if (key->data == NULL) + return ENOMEM; + key->length = keysize; + + for (i = 0; i < 64; i++) + pwbuf[i] = ((const unsigned char *)salt->data)[i % salt->length]; + + /* + * XXX This should really utf8/locale-string -> BMP string, time + * to import libwind. + */ + for (i = 0; i < 64; i += 2) { + pwbuf[i + 64] = 0; + pwbuf[i + 64 + 1] = pw[i % (pwlen + 1)]; /* include trailing zero */ + } + + p = key->data; + while (1) { + + SHA1_Init(&hash); + for (i = 0; i < 64; i++) + SHA_Update(&hash, &id, 1); + SHA1_Update(&hash, &pwbuf, 128); + SHA1_Final(hashout, &hash); + + for (i = 1; i < iterations; i++) { + SHA1_Init(&hash); + SHA1_Update(&hash, hashout, 20); + SHA1_Final(hashout, &hash); + } + memcpy(p, hashout, max(20, keysize - have_bytes)); + p += 20; + have_bytes += 20; + + if (have_bytes > keysize) + break; + + for (i = 0; i < 64; i++) + B[i] = hashout[i % 20]; + + /* */ + + } + + return 0; +} +#endif diff --git a/lib/hx509/crypto.c b/lib/hx509/crypto.c new file mode 100644 index 000000000..de86b6dcc --- /dev/null +++ b/lib/hx509/crypto.c @@ -0,0 +1,1312 @@ +/* + * Copyright (c) 2004 - 2005 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" +RCSID("$ID$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define pkcs1(name, number) \ +static unsigned name##_oid_data[] = { 1, 2, 840, 113549, 1, 1, number }; \ +static heim_oid name##_oid = { 7, name##_oid_data } + +pkcs1(rsaEncryption, 1); +pkcs1(md2WithRSAEncryption, 2); +pkcs1(md5WithRSAEncryption, 4); +pkcs1(sha1WithRSAEncryption, 5); + +#undef pkcs1 + +#define x9_57(name, number) \ +static unsigned name##_oid_data[] = { 1, 2, 840, 10040, 4, number }; \ +static heim_oid name##_oid = { 6, name##_oid_data } + +x9_57(id_dsa, 1); +x9_57(id_dsa_with_sha1, 3); + +#undef x9_57 + +#define oiw_secsig_alg(name, number) \ +static unsigned name##_oid_data[] = { 1, 3, 14, 3, 2, number }; \ +static heim_oid name##_oid = { 6, name##_oid_data } + +oiw_secsig_alg(id_sha1, 26); + +#undef oiw_secsig_alg + +#define rsadsi_digest(name, number) \ +static unsigned name##_oid_data[] = { 1, 2, 840, 113549, 2, number }; \ +static heim_oid name##_oid = { 6, name##_oid_data } + +rsadsi_digest(id_md2, 2); +rsadsi_digest(id_md5, 5); + +#undef rsadsi_digest + +#define private_oid(name, number) \ +static unsigned name##_oid_data[] = { 127, number }; \ +static heim_oid name##_oid = { 2, name##_oid_data } + +private_oid(private_rc2_40, 1); +/* private_oid(private_rc2_64, 2); */ + +#undef private_oid + +struct hx509_crypto; + +struct hx509_private_key { + EVP_PKEY *private_key; + /* supported key operations */ + /* context pointer to backend */ + /* function pointer to backend */ +}; + +/* + * + */ + +struct signature_alg { + char *name; + heim_oid *sig_oid; + heim_oid *key_oid; + const AlgorithmIdentifier *(*digest_alg)(void); + int flags; +#define PROVIDE_CONF 1 + int (*verify_signature)(const struct signature_alg *, + const Certificate *, + const AlgorithmIdentifier *, + const heim_octet_string *, + const heim_octet_string *); + int (*create_signature)(const struct signature_alg *, + const hx509_private_key, + const AlgorithmIdentifier *, + const heim_octet_string *, + AlgorithmIdentifier *, + heim_octet_string *); + int (*parse_private_key)(const struct signature_alg *, + const void *data, + size_t len, + hx509_private_key private_key); +}; + +/* + * + */ + +static BIGNUM * +heim_int2BN(const heim_integer *i) +{ + BIGNUM *bn; + + bn = BN_bin2bn(i->data, i->length, NULL); + bn->neg = i->negative; + return bn; +} + +static int +rsa_verify_signature(const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + const SubjectPublicKeyInfo *spi; + DigestInfo di; + unsigned char *to; + int tosize; + int ret; + RSA *rsa; + RSAPublicKey pk; + size_t size; + + memset(&di, 0, sizeof(di)); + + spi = &signer->tbsCertificate.subjectPublicKeyInfo; + + rsa = RSA_new(); + if (rsa == NULL) + return ENOMEM; + + ret = decode_RSAPublicKey(spi->subjectPublicKey.data, + spi->subjectPublicKey.length / 8, + &pk, &size); + if (ret) + goto out; + + rsa->n = heim_int2BN(&pk.modulus); + rsa->e = heim_int2BN(&pk.publicExponent); + + free_RSAPublicKey(&pk); + + if (rsa->n == NULL || rsa->e == NULL) { + ret = ENOMEM; + goto out; + } + + tosize = RSA_size(rsa); + to = malloc(tosize); + if (to == NULL) { + ret = ENOMEM; + goto out; + } + + ret = RSA_public_decrypt(sig->length, (unsigned char *)sig->data, + to, rsa, RSA_PKCS1_PADDING); + if (ret < 0) { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + free(to); + goto out; + } + if (ret > tosize) + abort(); + ret = decode_DigestInfo(to, ret, &di, &size); + free(to); + if (ret) { + goto out; + } + + if (sig_alg->digest_alg) { + const AlgorithmIdentifier *a = (*sig_alg->digest_alg)(); + + if (heim_oid_cmp(&di.digestAlgorithm.algorithm, &a->algorithm) != 0) { + ret = HX509_CRYPTO_OID_MISMATCH; + goto out; + } + } + + ret = _hx509_verify_signature(NULL, + &di.digestAlgorithm, + data, + &di.digest); + out: + free_DigestInfo(&di); + RSA_free(rsa); + return ret; +} + +static int +rsa_create_signature(const struct signature_alg *sig_alg, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_octet_string *sig) +{ + const EVP_MD *mdtype; + int len, ret; + const heim_oid *digest_oid, *sig_oid; + EVP_MD_CTX md; + + if (alg) + sig_oid = &alg->algorithm; + else + sig_oid = oid_id_pkcs1_sha1WithRSAEncryption(); + + if (heim_oid_cmp(sig_oid, oid_id_pkcs1_sha1WithRSAEncryption()) == 0) { + mdtype = EVP_sha1(); + digest_oid = oid_id_secsig_sha_1(); + } else if (heim_oid_cmp(sig_oid, oid_id_pkcs1_md5WithRSAEncryption()) == 0) { + mdtype = EVP_md5(); + digest_oid = oid_id_pkcs2_md5(); + } else + return HX509_ALG_NOT_SUPP; + + if (signatureAlgorithm) { + ret = _hx509_set_digest_alg(signatureAlgorithm, + sig_oid, "\x05\x00", 2); + if (ret) + return ret; + } + + sig->data = malloc(EVP_PKEY_size(signer->private_key)); + if (sig->data == NULL) + return ENOMEM; + + EVP_SignInit(&md, mdtype); + EVP_SignUpdate(&md, data->data, data->length); + ret = EVP_SignFinal(&md, sig->data, &len, signer->private_key); + if (ret != 1) { + free(sig->data); + sig->data = NULL; + return HX509_CMS_FAILED_CREATE_SIGATURE; + } + sig->length = len; + + return 0; +} + +static int +rsa_parse_private_key(const struct signature_alg *sig_alg, + const void *data, + size_t len, + hx509_private_key private_key) +{ + unsigned char *p = rk_UNCONST(data); + + private_key->private_key = d2i_PrivateKey(EVP_PKEY_RSA, NULL, &p, len); + if (private_key->private_key == NULL) + return EINVAL; + + return 0; +} + + +static int +dsa_verify_signature(const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + const SubjectPublicKeyInfo *spi; + DSAPublicKey pk; + DSAParams param; + size_t size; + DSA *dsa; + int ret; + + spi = &signer->tbsCertificate.subjectPublicKeyInfo; + + dsa = DSA_new(); + if (dsa) + return ENOMEM; + + ret = decode_DSAPublicKey(spi->subjectPublicKey.data, + spi->subjectPublicKey.length / 8, + &pk, &size); + if (ret) + goto out; + + dsa->pub_key = heim_int2BN(&pk); + + free_DSAPublicKey(&pk); + + if (dsa->pub_key == NULL) { + ret = ENOMEM; + goto out; + } + + if (spi->algorithm.parameters == NULL) { + ret = EINVAL; + goto out; + } + + ret = decode_DSAParams(spi->algorithm.parameters->data, + spi->algorithm.parameters->length, + ¶m, + &size); + if (ret) + goto out; + + dsa->p = heim_int2BN(¶m.p); + dsa->q = heim_int2BN(¶m.q); + dsa->g = heim_int2BN(¶m.g); + + free_DSAParams(¶m); + + if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) { + ret = ENOMEM; + goto out; + } + + ret = DSA_verify(-1, data->data, data->length, + (unsigned char*)sig->data, sig->length, + dsa); + if (ret == 1) + ret = 0; + else if (ret == 0 || ret == -1) + ret = HX509_CRYPTO_BAD_SIGNATURE; + else + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + + out: + DSA_free(dsa); + + return ret; +} + +static int +sha1_verify_signature(const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + char digest[SHA_DIGEST_LENGTH]; + SHA_CTX m; + + if (sig->length != SHA_DIGEST_LENGTH) + return HX509_CRYPTO_SIG_INVALID_FORMAT; + + SHA1_Init(&m); + SHA1_Update(&m, data->data, data->length); + SHA1_Final (digest, &m); + + if (memcmp(digest, sig->data, SHA_DIGEST_LENGTH) != 0) + return HX509_CRYPTO_BAD_SIGNATURE; + + return 0; +} + +static int +sha1_create_signature(const struct signature_alg *sig_alg, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_octet_string *sig) +{ + SHA_CTX m; + + memset(sig, 0, sizeof(*sig)); + + if (signatureAlgorithm) { + int ret; + ret = _hx509_set_digest_alg(signatureAlgorithm, + sig_alg->sig_oid, "\x05\x00", 2); + if (ret) + return ret; + } + + + sig->data = malloc(SHA_DIGEST_LENGTH); + if (sig->data == NULL) { + sig->length = 0; + return ENOMEM; + } + sig->length = SHA_DIGEST_LENGTH; + + SHA1_Init(&m); + SHA1_Update(&m, data->data, data->length); + SHA1_Final (sig->data, &m); + + return 0; +} + +static int +md5_verify_signature(const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + char digest[MD5_DIGEST_LENGTH]; + MD5_CTX m; + + if (sig->length != MD5_DIGEST_LENGTH) + return HX509_CRYPTO_SIG_INVALID_FORMAT; + + MD5_Init(&m); + MD5_Update(&m, data->data, data->length); + MD5_Final (digest, &m); + + if (memcmp(digest, sig->data, MD5_DIGEST_LENGTH) != 0) + return HX509_CRYPTO_BAD_SIGNATURE; + + return 0; +} + +static int +md2_verify_signature(const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + char digest[MD2_DIGEST_LENGTH]; + MD2_CTX m; + + if (sig->length != MD2_DIGEST_LENGTH) + return HX509_CRYPTO_SIG_INVALID_FORMAT; + + MD2_Init(&m); + MD2_Update(&m, data->data, data->length); + MD2_Final (digest, &m); + + if (memcmp(digest, sig->data, MD2_DIGEST_LENGTH) != 0) + return HX509_CRYPTO_BAD_SIGNATURE; + + return 0; +} + +static struct signature_alg pkcs1_rsa_sha1_alg = { + "rsa", + &rsaEncryption_oid, + &rsaEncryption_oid, + NULL, + PROVIDE_CONF, + rsa_verify_signature, + rsa_create_signature, + rsa_parse_private_key +}; + +static struct signature_alg rsa_with_sha1_alg = { + "rsa-with-sha1", + &sha1WithRSAEncryption_oid, + &rsaEncryption_oid, + hx509_signature_sha1, + PROVIDE_CONF, + rsa_verify_signature, + rsa_create_signature, + rsa_parse_private_key +}; + +static struct signature_alg rsa_with_md5_alg = { + "rsa-with-md5", + &md5WithRSAEncryption_oid, + &rsaEncryption_oid, + hx509_signature_md5, + PROVIDE_CONF, + rsa_verify_signature, + rsa_create_signature, + rsa_parse_private_key +}; + +static struct signature_alg rsa_with_md2_alg = { + "rsa-with-md2", + &md2WithRSAEncryption_oid, + &rsaEncryption_oid, + hx509_signature_md2, + PROVIDE_CONF, + rsa_verify_signature, + rsa_create_signature, + rsa_parse_private_key +}; + +static struct signature_alg dsa_sha1_alg = { + "dsa-with-sha1", + &id_dsa_with_sha1_oid, + &id_dsa_oid, + hx509_signature_sha1, + PROVIDE_CONF, + dsa_verify_signature +}; + +static struct signature_alg sha1_alg = { + "sha1", + &id_sha1_oid, + NULL, + NULL, + 0, + sha1_verify_signature, + sha1_create_signature +}; + +static struct signature_alg md5_alg = { + "rsa-md5", + &id_md5_oid, + NULL, + NULL, + 0, + md5_verify_signature +}; + +static struct signature_alg md2_alg = { + "rsa-md2", + &id_md2_oid, + NULL, + NULL, + 0, + md2_verify_signature +}; + +static struct signature_alg *sig_algs[] = { + &pkcs1_rsa_sha1_alg, + &rsa_with_sha1_alg, + &rsa_with_md5_alg, + &rsa_with_md2_alg, + &dsa_sha1_alg, + &sha1_alg, + &md5_alg, + &md2_alg, + 0, + NULL +}; + +static const struct signature_alg * +find_sig_alg(const heim_oid *oid) +{ + int i; + for (i = 0; sig_algs[i]; i++) + if (heim_oid_cmp(sig_algs[i]->sig_oid, oid) == 0) + return sig_algs[i]; + return NULL; +} + +static const struct signature_alg * +find_key_alg(const heim_oid *oid) +{ + int i; + for (i = 0; sig_algs[i]; i++) + if (heim_oid_cmp(sig_algs[i]->key_oid, oid) == 0) + return sig_algs[i]; + return NULL; +} + +int +_hx509_verify_signature(const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + const struct signature_alg *md; + + md = find_sig_alg(&alg->algorithm); + if (md == NULL) { + return HX509_SIG_ALG_NO_SUPPORTED; + } + if (signer && (md->flags & PROVIDE_CONF) == 0) + return HX509_CRYPTO_SIG_NO_CONF; + if (md->key_oid) { + const SubjectPublicKeyInfo *spi; + spi = &signer->tbsCertificate.subjectPublicKeyInfo; + + if (heim_oid_cmp(&spi->algorithm.algorithm, md->key_oid) != 0) + return HX509_SIG_ALG_DONT_MATCH_KEY_ALG; + } + return (*md->verify_signature)(md, signer, alg, data, sig); +} + +const AlgorithmIdentifier * +_hx509_digest_signature(const AlgorithmIdentifier *alg) +{ + const struct signature_alg *md; + md = find_sig_alg(&alg->algorithm); + if (md && md->digest_alg) + return (*md->digest_alg)(); + return NULL; +} + +int +_hx509_create_signature(const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_octet_string *sig) +{ + const struct signature_alg *md; + + md = find_sig_alg(&alg->algorithm); + if (md == NULL) + return HX509_SIG_ALG_NO_SUPPORTED; + + if (signer && (md->flags & PROVIDE_CONF) == 0) + return HX509_CRYPTO_SIG_NO_CONF; + + return (*md->create_signature)(md, signer, alg, data, + signatureAlgorithm, sig); +} + +int +_hx509_public_encrypt(const heim_octet_string *cleartext, + const Certificate *cert, + heim_oid *encryption_oid, + heim_octet_string *ciphertext) +{ + const SubjectPublicKeyInfo *spi; + unsigned char *to; + int tosize; + int ret; + RSA *rsa; + RSAPublicKey pk; + size_t size; + + ciphertext->data = NULL; + ciphertext->length = 0; + + spi = &cert->tbsCertificate.subjectPublicKeyInfo; + + rsa = RSA_new(); + if (rsa == NULL) + return ENOMEM; + + ret = decode_RSAPublicKey(spi->subjectPublicKey.data, + spi->subjectPublicKey.length / 8, + &pk, &size); + if (ret) { + RSA_free(rsa); + return ENOMEM; + } + rsa->n = heim_int2BN(&pk.modulus); + rsa->e = heim_int2BN(&pk.publicExponent); + + free_RSAPublicKey(&pk); + + if (rsa->n == NULL || rsa->e == NULL) { + RSA_free(rsa); + return ENOMEM; + } + + tosize = RSA_size(rsa); + to = malloc(tosize); + if (to == NULL) { + RSA_free(rsa); + return ENOMEM; + } + + ret = RSA_public_encrypt(cleartext->length, + (unsigned char *)cleartext->data, + to, rsa, RSA_PKCS1_PADDING); + RSA_free(rsa); + if (ret < 0) { + free(to); + return EINVAL; + } + if (ret > tosize) + abort(); + + ciphertext->length = ret; + ciphertext->data = to; + + ret = copy_oid(&rsaEncryption_oid, encryption_oid); + if (ret) { + free_octet_string(ciphertext); + return ENOMEM; + } + + return 0; +} + +int +_hx509_private_key_private_decrypt(const heim_octet_string *ciphertext, + const heim_oid *encryption_oid, + hx509_private_key p, + heim_octet_string *cleartext) +{ + unsigned char *buf; + int ret; + + cleartext->data = NULL; + cleartext->length = 0; + + if (p->private_key == NULL) + return EINVAL; + + buf = malloc(EVP_PKEY_size(p->private_key)); + if (buf == NULL) + return ENOMEM; + + ret = EVP_PKEY_decrypt(buf, + ciphertext->data, + ciphertext->length, + p->private_key); + if (ret <= 0) { + free(buf); + return ENOMEM; /* XXX */ + } + + cleartext->data = realloc(buf, ret); + if (cleartext->data == NULL) { + free(buf); + return ENOMEM; + } + cleartext->length = ret; + return 0; +} + + +int +_hx509_parse_private_key(const heim_oid *key_oid, + const void *data, + size_t len, + hx509_private_key *private_key) +{ + const struct signature_alg *md; + int ret; + + md = find_key_alg(key_oid); + if (md == NULL) + return HX509_SIG_ALG_NO_SUPPORTED; + + ret = _hx509_new_private_key(private_key); + if (ret) + return ret; + + ret = (*md->parse_private_key)(md, data, len, *private_key); + if (ret) + _hx509_free_private_key(private_key); + + return ret; +} + +/* + * + */ + +static const unsigned sha1_oid_tree[] = { 1, 3, 14, 3, 2, 26 }; +const AlgorithmIdentifier _hx509_signature_sha1_data = { + { 6, rk_UNCONST(sha1_oid_tree) }, NULL +}; + +static const unsigned md5_oid_tree[] = { 1, 2, 840, 113549, 2, 5 }; +const AlgorithmIdentifier _hx509_signature_md5_data = { + { 6, rk_UNCONST(md5_oid_tree) }, NULL +}; + +static const unsigned md2_oid_tree[] = { 1, 2, 840, 113549, 2, 2 }; +const AlgorithmIdentifier _hx509_signature_md2_data = { + { 6, rk_UNCONST(md2_oid_tree) }, NULL +}; + +static const unsigned rsa_with_sha1_oid[] ={ 1, 2, 840, 113549, 1, 1, 5 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha1_data = { + { 7, rk_UNCONST(rsa_with_sha1_oid) }, NULL +}; + + +const AlgorithmIdentifier * +hx509_signature_sha1(void) +{ + return &_hx509_signature_sha1_data; +} + +const AlgorithmIdentifier * +hx509_signature_md5(void) +{ + return &_hx509_signature_md5_data; +} + +const AlgorithmIdentifier * +hx509_signature_md2(void) +{ + return &_hx509_signature_md2_data; +} + +const AlgorithmIdentifier * +hx509_signature_rsa_with_sha1(void) +{ + return &_hx509_signature_rsa_with_sha1_data; +} + +int +_hx509_new_private_key(hx509_private_key *key) +{ + *key = calloc(1, sizeof(**key)); + if (*key == NULL) + return ENOMEM; + return 0; +} + +int +_hx509_free_private_key(hx509_private_key *key) +{ + if ((*key)->private_key) + EVP_PKEY_free((*key)->private_key); + (*key)->private_key = NULL; + free(*key); + return 0; +} + +int +_hx509_private_key_assign_key_file(hx509_private_key key, + hx509_lock lock, + const char *fn) +{ + const struct _hx509_password *pw; + int i; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + pw = _hx509_lock_get_passwords(lock); + + for (i = 0; i < pw->len; i++) { + FILE *f; + + f = fopen(fn, "r"); + if (f == NULL) + return ENOMEM; + + key->private_key = PEM_read_PrivateKey(f, NULL, NULL, pw->val[i]); + fclose(f); + if (key->private_key == NULL) { + printf("failed to read private key: %s\n", + ERR_error_string(ERR_get_error(), NULL)); + return ENOENT; + } + } + + return 0; +} + +struct hx509_crypto_data { + char *name; + const EVP_CIPHER *c; + heim_octet_string key; + heim_oid oid; +}; + +static const EVP_CIPHER * +find_cipher(const heim_oid *oid) +{ + if (heim_oid_cmp(oid, oid_id_pkcs3_rc2_cbc()) == 0) { + return EVP_rc2_cbc(); + } else if (heim_oid_cmp(oid, &private_rc2_40_oid) == 0) { + return EVP_rc2_40_cbc(); + } else if (heim_oid_cmp(oid, oid_id_pkcs3_des_ede3_cbc()) == 0) { + return EVP_des_ede3_cbc(); + } else if (heim_oid_cmp(oid, oid_id_rsadsi_des_ede3_cbc()) == 0) { + return EVP_des_ede3_cbc(); + } else if (heim_oid_cmp(oid, oid_id_aes_128_cbc()) == 0) { + return EVP_aes_128_cbc(); + } else if (heim_oid_cmp(oid, oid_id_aes_192_cbc()) == 0) { + return EVP_aes_192_cbc(); + } else if (heim_oid_cmp(oid, oid_id_aes_256_cbc()) == 0) { + return EVP_aes_256_cbc(); + } + return NULL; +} + +int +hx509_crypto_init(const char *provider, + const heim_oid *enctype, + hx509_crypto *crypto) +{ + const EVP_CIPHER *c; + + *crypto = NULL; + + c = find_cipher(enctype); + if (c == NULL) + return HX509_ALG_NOT_SUPP; + + *crypto = calloc(1, sizeof(**crypto)); + if (*crypto == NULL) + return ENOMEM; + + (*crypto)->c = c; + + if (copy_oid(enctype, &(*crypto)->oid)) { + hx509_crypto_destroy(*crypto); + return ENOMEM; + } + + return 0; +} + +const char * +hx509_crypto_provider(hx509_crypto crypto) +{ + return "unknown"; +} + +void +hx509_crypto_destroy(hx509_crypto crypto) +{ + if (crypto->name) + free(crypto->name); + if (crypto->key.data) + free(crypto->key.data); + memset(crypto, 0, sizeof(*crypto)); + free(crypto); +} + +int +hx509_crypto_set_key_name(hx509_crypto crypto, const char *name) +{ + return 0; +} + +int +hx509_crypto_set_key_data(hx509_crypto crypto, const void *data, size_t length) +{ + if (EVP_CIPHER_key_length(crypto->c) > length) + return HX509_CRYPTO_INTERNAL_ERROR; + + if (crypto->key.data) { + free(crypto->key.data); + crypto->key.length = 0; + } + crypto->key.data = malloc(length); + if (crypto->key.data == NULL) + return ENOMEM; + memcpy(crypto->key.data, data, length); + crypto->key.length = length; + + return 0; +} + +int +hx509_crypto_set_random_key(hx509_crypto crypto, heim_octet_string *key) +{ + if (crypto->key.data) { + free(crypto->key.data); + crypto->key.length = 0; + } + + crypto->key.length = EVP_CIPHER_key_length(crypto->c); + crypto->key.data = malloc(crypto->key.length); + if (crypto->key.data == NULL) { + crypto->key.length = 0; + return ENOMEM; + } + if (RAND_bytes(crypto->key.data, crypto->key.length) <= 0) { + free(crypto->key.data); + crypto->key.length = 0; + return HX509_CRYPTO_INTERNAL_ERROR; + } + if (key) + return copy_octet_string(&crypto->key, key); + else + return 0; +} + +int +hx509_crypto_set_params(hx509_crypto crypto, + const heim_octet_string *param, + heim_octet_string *ivec) +{ + if (ivec == NULL) + return 0; + return decode_CMSCBCParameter(param->data, param->length, ivec, NULL); +} + +int +hx509_crypto_get_params(hx509_crypto crypto, + const heim_octet_string *ivec, + heim_octet_string *param) +{ + int ret; + size_t size; + + ASN1_MALLOC_ENCODE(CMSCBCParameter, + param->data, + param->length, + ivec, + &size, + ret); + if (ret) + return ret; + if (param->length != size) + abort(); + return 0; +} + + +int +hx509_crypto_encrypt(hx509_crypto crypto, + const void *data, + const size_t length, + heim_octet_string *ivec, + heim_octet_string **ciphertext) +{ + EVP_CIPHER_CTX evp; + size_t padsize; + int ret; + + *ciphertext = NULL; + + EVP_CIPHER_CTX_init(&evp); + + ivec->length = EVP_CIPHER_iv_length(crypto->c); + ivec->data = malloc(ivec->length); + if (ivec->data == NULL) { + ret = ENOMEM; + goto out; + } + + if (RAND_bytes(ivec->data, ivec->length) <= 0) { + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + + if (EVP_CipherInit(&evp,crypto->c,crypto->key.data,ivec->data, 1) != 1) { + EVP_CIPHER_CTX_cleanup(&evp); + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + + *ciphertext = calloc(1, sizeof(**ciphertext)); + if (*ciphertext == NULL) { + ret = ENOMEM; + goto out; + } + + if (EVP_CIPHER_block_size(crypto->c) == 1) { + padsize = 0; + } else { + int bsize = EVP_CIPHER_block_size(crypto->c); + padsize = bsize - (length % bsize); + } + (*ciphertext)->length = length + padsize; + (*ciphertext)->data = malloc(length + padsize); + if ((*ciphertext)->data == NULL) { + ret = ENOMEM; + goto out; + } + + memcpy((*ciphertext)->data, data, length); + if (padsize) { + int i; + unsigned char *p = (*ciphertext)->data; + p += length; + for (i = 0; i < padsize; i++) + *p++ = padsize; + } + + ret = EVP_Cipher(&evp, (*ciphertext)->data, + (*ciphertext)->data, + length + padsize); + if (ret != 1) { + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + ret = 0; + + out: + if (ret) { + if (ivec->data) { + free(ivec->data); + memset(ivec, 0, sizeof(*ivec)); + } + if (ciphertext) { + if ((*ciphertext)->data) { + free((*ciphertext)->data); + } + free(*ciphertext); + *ciphertext = NULL; + } + } + EVP_CIPHER_CTX_cleanup(&evp); + + return ret; +} + +int +hx509_crypto_decrypt(hx509_crypto crypto, + const void *data, + const size_t length, + heim_octet_string *ivec, + heim_octet_string *clear) +{ + EVP_CIPHER_CTX evp; + void *idata = NULL; + int ret; + + clear->data = NULL; + clear->length = 0; + + if (ivec && EVP_CIPHER_iv_length(crypto->c) < ivec->length) + return HX509_CRYPTO_INTERNAL_ERROR; + + if (crypto->key.data == NULL) + return HX509_CRYPTO_INTERNAL_ERROR; + + if (ivec) + idata = ivec->data; + + EVP_CIPHER_CTX_init(&evp); + + if (EVP_CipherInit(&evp, crypto->c, crypto->key.data, idata, 0) != 1) { + EVP_CIPHER_CTX_cleanup(&evp); + return HX509_CRYPTO_INTERNAL_ERROR; + } + + clear->length = length; + clear->data = malloc(length); + if (clear->data == NULL) { + EVP_CIPHER_CTX_cleanup(&evp); + clear->length = 0; + return ENOMEM; + } + + if (EVP_Cipher(&evp, clear->data, data, length) != 1) { + return HX509_CRYPTO_INTERNAL_ERROR; + } + EVP_CIPHER_CTX_cleanup(&evp); + + if (EVP_CIPHER_block_size(crypto->c) > 1) { + int padsize; + unsigned char *p; + int j, bsize = EVP_CIPHER_block_size(crypto->c); + + if (clear->length < bsize) { + ret = HX509_CMS_PADDING_ERROR; + goto out; + } + + p = clear->data; + p += clear->length - 1; + padsize = *p; + if (padsize > bsize) { + ret = HX509_CMS_PADDING_ERROR; + goto out; + } + clear->length -= padsize; + for (j = 0; j < padsize; j++) { + if (*p-- != padsize) { + ret = HX509_CMS_PADDING_ERROR; + goto out; + } + } + } + + return 0; + + out: + if (clear->data) + free(clear->data); + clear->data = NULL; + clear->length = 0; + return ret; +} + +static const heim_oid * +find_string2key(const heim_oid *oid, const EVP_CIPHER **c) +{ + if (heim_oid_cmp(oid, oid_id_pbewithSHAAnd40BitRC2_CBC()) == 0) { + *c = EVP_rc2_40_cbc(); + return &private_rc2_40_oid; + } else if (heim_oid_cmp(oid, oid_id_pbeWithSHAAnd128BitRC2_CBC()) == 0) { + *c = EVP_rc2_cbc(); + return oid_id_pkcs3_rc2_cbc(); + } else if (heim_oid_cmp(oid, oid_id_pbeWithSHAAnd40BitRC4()) == 0) { + *c = EVP_rc4_40(); + return NULL; + } else if (heim_oid_cmp(oid, oid_id_pbeWithSHAAnd128BitRC4()) == 0) { + *c = EVP_rc4(); + return oid_id_pkcs3_rc4(); + } else if (heim_oid_cmp(oid, oid_id_pbeWithSHAAnd3_KeyTripleDES_CBC()) == 0) { + *c = EVP_des_ede3_cbc(); + return oid_id_pkcs3_des_ede3_cbc(); + } + + return NULL; +} + + +int +_hx509_pbe_decrypt(const char *password, + const AlgorithmIdentifier *ai, + const heim_octet_string *econtent, + heim_octet_string *content) +{ + heim_octet_string key, iv; + const heim_oid *enc_oid; + const EVP_CIPHER *c; + int ret; + + PKCS12_PBEParams params; + int iter; + unsigned char *salt; + int saltlen; + int passlen = strlen(password); + + memset(&key, 0, sizeof(key)); + memset(&iv, 0, sizeof(iv)); + + memset(content, 0, sizeof(*content)); + + enc_oid = find_string2key(&ai->algorithm, &c); + if (enc_oid == NULL) { + ret = HX509_ALG_NOT_SUPP; + goto out; + } + + ret = decode_PKCS12_PBEParams(ai->parameters->data, ai->parameters->length, + ¶ms, NULL); + if (ret) { + goto out; + } + if (params.iterations) + iter = *params.iterations; + else + iter = 1; + salt = params.salt.data; + saltlen = params.salt.length; + + key.length = EVP_CIPHER_key_length(c); + key.data = malloc(key.length); + + iv.length = EVP_CIPHER_iv_length(c); + iv.data = malloc(iv.length); + + { + const EVP_MD *md = EVP_sha1(); + hx509_crypto crypto; + + if (!PKCS12_key_gen (password, passlen, salt, saltlen, PKCS12_KEY_ID, + iter, key.length, key.data, md)) { + free_PKCS12_PBEParams(¶ms); + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + + if (!PKCS12_key_gen (password, passlen, salt, saltlen, PKCS12_IV_ID, + iter, iv.length, iv.data, md)) { + free_PKCS12_PBEParams(¶ms); + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + free_PKCS12_PBEParams(¶ms); + + ret = hx509_crypto_init(NULL, + enc_oid, + &crypto); + if (ret) + goto out; + + ret = hx509_crypto_set_key_data(crypto, key.data, key.length); + if (ret) { + hx509_crypto_destroy(crypto); + goto out; + } + + ret = hx509_crypto_decrypt(crypto, + econtent->data, + econtent->length, + &iv, + content); + hx509_crypto_destroy(crypto); + if (ret) + goto out; + + } + out: + free_octet_string(&key); + free_octet_string(&iv); + return ret; +} diff --git a/lib/hx509/file.c b/lib/hx509/file.c new file mode 100644 index 000000000..d81851130 --- /dev/null +++ b/lib/hx509/file.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2005 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" +RCSID("$ID$"); + +int +_hx509_map_file(const char *fn, void **data, size_t *length) +{ + struct stat sb; + size_t len; + ssize_t l; + int ret; + void *d; + int fd; + + *data = NULL; + *length = 0; + + fd = open(fn, O_RDONLY); + if (fd < 0) + return errno; + + if (fstat(fd, &sb) < 0) { + ret = errno; + close(fd); + return ret; + } + + len = sb.st_size; + + d = malloc(len); + if (d == NULL) { + close(fd); + return ENOMEM; + } + + l = read(fd, d, len); + close(fd); + if (l < 0 || l != len) { + free(d); + return EINVAL; + } + + *data = d; + *length = len; + return 0; +} + +void +_hx509_unmap_file(void *data, size_t len) +{ + free(data); +} diff --git a/lib/hx509/hx509.h b/lib/hx509/hx509.h new file mode 100644 index 000000000..f6547a914 --- /dev/null +++ b/lib/hx509/hx509.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2004 - 2005 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. + */ + +/* $Id$ */ + +typedef struct hx509_verify_ctx_data *hx509_verify_ctx; +typedef struct hx509_certs_data *hx509_certs; +typedef struct hx509_cert_data *hx509_cert; +typedef struct hx509_cert_attribute_data *hx509_cert_attribute; +typedef struct hx509_validate_ctx_data *hx509_validate_ctx; +typedef struct hx509_name_data *hx509_name; +typedef void * hx509_cursor; +typedef struct hx509_lock_data *hx509_lock; +typedef struct hx509_private_key *hx509_private_key; + +/* current unused */ +typedef struct hx509_crypto_data *hx509_crypto; +typedef struct hx509_digest_data *hx509_digest; + +typedef void (*hx509_vprint_func)(void *, const char *, va_list); + +enum { + HX509_VALIDATE_F_VALIDATE = 1, + HX509_VALIDATE_F_VERBOSE = 2 +}; + +struct hx509_cert_attribute_data { + heim_oid oid; + heim_octet_string data; +}; + +typedef enum { + HX509_PROMPT_TYPE_PASSWORD = 0x1, + HX509_PROMPT_TYPE_QUESTION = 0x2, + HX509_PROMPT_TYPE_CONFIRMATION = 0x4 +} hx509_prompt_type; + +typedef struct hx509_prompt { + const char *prompt; + int hidden; + hx509_prompt_type type; + heim_octet_string *reply; +} hx509_prompt; + +typedef int (*hx509_prompter_fct)(void *, const hx509_prompt *); + +#include diff --git a/lib/hx509/hx509_err.et b/lib/hx509/hx509_err.et new file mode 100644 index 000000000..73fdf796e --- /dev/null +++ b/lib/hx509/hx509_err.et @@ -0,0 +1,49 @@ +# +# Error messages for the hx509 library +# +# This might look like a com_err file, but is not +# +id "$Id$" + +error_table hx +prefix HX509 + +error_code BAD_TIMEFORMAT, "ASN.1 failed call to system time library" +error_code EXTENSION_NOT_FOUND, "Extension not found" +error_code NO_PATH, "Certification path not found" +error_code PARENT_NOT_CA, "Parent certificate is not a CA" +error_code CA_PATH_TOO_DEEP, "CA path too deep" +error_code SIG_ALG_NO_SUPPORTED, "Signature algorithm not supported" +error_code SIG_ALG_DONT_MATCH_KEY_ALG, "Signature algorithm doesn't match certificate key" +error_code CERT_USED_BEFORE_TIME, "Certificate used before it became valid" +error_code CERT_USED_AFTER_TIME, "Certificate used after it became invalid" +error_code PRIVATE_KEY_MISSING, "Private key required for the operation is missing" +error_code ALG_NOT_SUPP, "Algorithm not supported" +error_code ISSUER_NOT_FOUND, "Issuer couldn't be found" +error_code VERIFY_CONSTRAINTS, "Error verifing constraints" +error_code RANGE, "Number too large" +error_code NAME_CONSTRAINT_ERROR, "Error while verifing name constraints" +error_code PATH_TOO_LONG, "Path is too long, failed to find valid anchor" + +index 32 +prefix HX509_CMS +error_code FAILED_CREATE_SIGATURE, "Failed to create signature" +error_code MISSING_SIGNER_DATA, "Missing signer data" +error_code SIGNER_NOT_FOUND, "Couldn't find signers certificate" +error_code NO_DATA_AVAILABLE, "No data to perform the operation on" +error_code INVALID_DATA, "Data in the message is invalid" +error_code PADDING_ERROR, "Padding in the message invalid" +error_code NO_RECIPIENT_CERTIFICATE, "Couldn't find recipient certificate" +error_code DATA_OID_MISMATCH, "Mismatch bewteen signed type and unsigned type" + +index 64 +prefix HX509_CRYPTO +error_code INTERNAL_ERROR, "Internal error in the crypto engine" +error_code EXTERNAL_ERROR, "External error in the crypto engine" +error_code SIGNATURE_MISSING, "Signature missing for data" +error_code BAD_SIGNATURE, "Signature is not valid" +error_code SIG_NO_CONF, "Sigature doesn't provide confidentiality" +error_code SIG_INVALID_FORMAT, "Invalid format on signature" +error_code OID_MISMATCH, "Mismatch bewteen oids" + +end diff --git a/lib/hx509/hx_locl.h b/lib/hx509/hx_locl.h new file mode 100644 index 000000000..e98858eb3 --- /dev/null +++ b/lib/hx509/hx_locl.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2004 - 2005 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. + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct hx509_query_data; +typedef struct hx509_query_data hx509_query; + +struct hx509_keyset_ops; + +#include +#include +#include + +#define HX509_CERTS_FIND_SERIALNUMBER 1 +#define HX509_CERTS_FIND_ISSUER 2 +#define HX509_CERTS_FIND_SUBJECT 4 +#define HX509_CERTS_FIND_ISSUER_KEY_ID 8 +#define HX509_CERTS_FIND_SUBJECT_KEY_ID 16 + +struct hx509_name_data { + Name der_name; +}; + +typedef struct hx509_path { + size_t len; + hx509_cert *val; +} hx509_path; + +struct hx509_query_data { + int match; +#define HX509_QUERY_FIND_ISSUER_CERT 0x001 +#define HX509_QUERY_MATCH_SERIALNUMBER 0x002 +#define HX509_QUERY_MATCH_ISSUER_NAME 0x004 +#define HX509_QUERY_MATCH_SUBJECT_NAME 0x008 +#define HX509_QUERY_MATCH_SUBJECT_ID 0x010 +#define HX509_QUERY_MATCH_ISSUER_ID 0x020 +#define HX509_QUERY_PRIVATE_KEY 0x040 +#define HX509_QUERY_ANCHOR 0x080 +#define HX509_QUERY_MATCH_CERTIFICATE 0x100 +#define HX509_QUERY_MATCH_LOCAL_KEY_ID 0x200 +#define HX509_QUERY_NO_MATCH_PATH 0x400 +#define HX509_QUERY_MASK 0x7ff + Certificate *subject; + Certificate *certificate; + heim_integer *serial; + heim_octet_string *subject_id; + heim_octet_string *local_key_id; + Name *issuer_name; + Name *subject_name; + hx509_path *path; +}; + +struct hx509_keyset_ops { + char *name; + int flags; + int (*init)(hx509_certs, void **, int, const char *, hx509_lock); + int (*free)(hx509_certs, void *); + int (*add)(hx509_certs, void *, hx509_cert); + int (*query)(hx509_certs, void *, const hx509_query *, hx509_cert *); + int (*iter_start)(hx509_certs, void *, void **); + int (*iter)(hx509_certs, void *, void *, hx509_cert *); + int (*iter_end)(hx509_certs, void *, void *); +}; + +struct _hx509_password { + size_t len; + char **val; +}; + +extern hx509_lock _hx509_empty_lock; diff --git a/lib/hx509/hxtool.c b/lib/hx509/hxtool.c new file mode 100644 index 000000000..f1879a401 --- /dev/null +++ b/lib/hx509/hxtool.c @@ -0,0 +1,549 @@ +/* + * Copyright (c) 2004 - 2005 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" +RCSID("$ID$"); + +#include + +static int version_flag; +static int help_flag; + +struct getargs args[] = { + { "version", 0, arg_flag, &version_flag }, + { "help", 0, arg_flag, &help_flag } +}; +int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int code) +{ + arg_printusage(args, num_args, NULL, "command"); + exit(code); +} + +static int +cms_verify_sd(int argc, char **argv) +{ + int ret; + hx509_verify_ctx ctx = NULL; + heim_oid type; + heim_octet_string c; + hx509_certs signers = NULL; + hx509_certs anchors = NULL; + + ssize_t sz; + void *p; + int fd; + + argc--; + argv++; + + if (argc < 2) + errx(1, "argc < 2"); + + printf("cms verify signed data\n"); + + fd = open(argv[0], O_RDONLY, 0); + if (fd < 0) + err(1, "open %s", argv[0]); + + p = malloc(10000); + if (p == NULL) + ; + + sz = read(fd, p, 10000); + if (sz < 0) + err(1, "read"); + close(fd); + + + ret = hx509_verify_init_ctx(&ctx); + + argc--; + argv++; + + ret = hx509_certs_init("MEMORY:cms-anchors", 0, NULL, &anchors); + + while (argc > 0) { + + ret = hx509_certs_append(anchors, argv[0]); + if (ret) + errx(1, "hx509_certs_append: %d", ret); + + argc--; + argv++; + } + + hx509_verify_attach_anchors(ctx, anchors); + + ret = hx509_cms_verify_signed(ctx, p, sz, &type, &c, &signers); + if (ret) + errx(1, "hx509_cms_verify_signed: %d", ret); + + printf("signers:\n"); + hx509_certs_iter(signers, hx509_ci_print_names, stdout); + + hx509_certs_free(&anchors); + hx509_certs_free(&signers); + + return 0; +} + +static int +cms_create_sd(int argc, char **argv) +{ + const heim_oid *contentType; + heim_octet_string o; + hx509_query q; + hx509_lock lock; + hx509_certs s; + hx509_cert cert; + ssize_t sz; + void *p; + int fd; + int ret; + + contentType = oid_id_pkcs7_data(); + + argc--; + argv++; + + if (argc < 3) + errx(1, "argc < 3"); + + printf("cms create signed data\n"); + + hx509_lock_init(&lock); + hx509_lock_add_password(lock, "foobar"); + + fd = open(argv[0], O_RDONLY, 0); + if (fd < 0) + err(1, "open %s", argv[0]); + + p = malloc(10000); + if (p == NULL) + ; + + sz = read(fd, p, 10000); + if (sz < 0) + err(1, "read"); + close(fd); + + ret = hx509_certs_init(argv[2], 0, lock, &s); + if (ret) + errx(1, "hx509_certs_init: %d", ret); + + _hx509_query_clear(&q); + q.match |= HX509_QUERY_PRIVATE_KEY; + + ret = _hx509_certs_find(s, &q, &cert); + if (ret) + errx(1, "hx509_certs_find: %d", ret); + + ret = hx509_cms_create_signed_1(contentType, + p, + sz, + NULL, + cert, + &o); + if (ret) + errx(1, "hx509_cms_create_signed: %d", ret); + + fd = open(argv[1], O_WRONLY|O_TRUNC|O_CREAT, 0644); + if (fd < 0) + err(1, "open %s", argv[1]); + + write(fd, o.data, o.length); + close(fd); + + hx509_lock_free(lock); + + return 0; +} + +static int +cms_unenvelope(int argc, char **argv) +{ + heim_oid contentType = { 0, NULL }; + heim_octet_string o; + hx509_certs certs; + ssize_t sz; + void *p; + int fd; + int ret; + hx509_lock lock; + + argc--; + argv++; + + if (argc != 3) + errx(1, "argc != 3"); + + printf("cms unenvelope data\n"); + + hx509_lock_init(&lock); + hx509_lock_add_password(lock, "foobar"); + + fd = open(argv[1], O_RDONLY, 0); + if (fd < 0) + err(1, "open %s", argv[1]); + + p = malloc(10000); + if (p == NULL) + ; + + sz = read(fd, p, 10000); + if (sz < 0) + err(1, "read"); + close(fd); + + ret = hx509_certs_init("MEMORY:cert-store", 0, NULL, &certs); + + ret = hx509_certs_init(argv[0], 0, lock, &certs); + if (ret) + errx(1, "hx509_certs_init: %d", ret); + + ret = hx509_cms_unenvelope(certs, p, sz, &contentType, &o); + if (ret) + errx(1, "hx509_cms_unenvelope: %d", ret); + + fd = open(argv[2], O_WRONLY|O_TRUNC|O_CREAT, 0644); + if (fd < 0) + err(1, "open %s", argv[2]); + + write(fd, o.data, o.length); + close(fd); + + hx509_lock_free(lock); + + return 0; +} + +static int +cms_create_enveloped(int argc, char **argv) +{ + heim_octet_string o; + heim_oid contentType = { 0, NULL }; + hx509_query q; + hx509_certs certs; + hx509_cert cert; + int ret; + ssize_t sz; + void *p; + int fd; + + argc--; + argv++; + + if (argc != 3) + errx(1, "argc ! = 3"); + + printf("cms create enveloped\n"); + + fd = open(argv[0], O_RDONLY, 0); + if (fd < 0) + err(1, "open %s", argv[0]); + + p = malloc(10000); + if (p == NULL) + ; + + sz = read(fd, p, 10000); + if (sz < 0) + err(1, "read"); + close(fd); + + ret = hx509_certs_init(argv[2], 0, NULL, &certs); + if (ret) + errx(1, "hx509_certs_init: %d", ret); + + _hx509_query_clear(&q); + ret = _hx509_certs_find(certs, &q, &cert); + if (ret) + errx(1, "hx509_certs_find: %d", ret); + + ret = hx509_cms_envelope_1(cert, p, sz, NULL, &contentType, &o); + if (ret) + errx(1, "hx509_cms_unenvelope: %d", ret); + + fd = open(argv[1], O_WRONLY|O_TRUNC|O_CREAT, 0644); + if (fd < 0) + err(1, "open %s", argv[1]); + + write(fd, o.data, o.length); + close(fd); + + return 0; +} + +static int +validate_print_f(void *ctx, hx509_cert c) +{ + hx509_validate_cert(ctx, c); + return 0; +} + +static int +validate_print(int argc, char **argv, int flags) +{ + hx509_validate_ctx ctx; + hx509_certs certs; + hx509_lock lock; + + argc--; + argv++; + + if (argc < 1) + errx(1, "argc"); + + hx509_lock_init(&lock); + hx509_lock_add_password(lock, "foobar"); + + hx509_validate_ctx_init(&ctx); + hx509_validate_ctx_set_print(ctx, hx509_print_stdout, stdout); + hx509_validate_ctx_add_flags(ctx, flags); + + while(argc--) { + int ret; + ret = hx509_certs_init(argv[0], 0, lock, &certs); + if (ret) + errx(1, "hx509_certs_init"); + hx509_certs_iter(certs, validate_print_f, ctx); + hx509_certs_free(&certs); + argv++; + } + hx509_validate_ctx_free(ctx); + + hx509_lock_free(lock); + + return 0; +} + +static int +pcert_print(int argc, char **argv) +{ + return validate_print(argc, argv, HX509_VALIDATE_F_VERBOSE); +} + +static int +pcert_validate(int argc, char **argv) +{ + return validate_print(argc, argv, HX509_VALIDATE_F_VALIDATE); +} + +struct verify { + hx509_verify_ctx ctx; + hx509_certs chain; +}; + +static int +verify_f(void *ctx, hx509_cert c) +{ + struct verify *v = ctx; + int ret; + + ret = hx509_verify_path(v->ctx, c, v->chain); + if (ret) + printf("verify_path returned %d\n", ret); + else + printf("path ok\n"); + + return 0; +} + +static int +pcert_verify(int argc, char **argv) +{ + hx509_certs anchors, chain, certs; + hx509_verify_ctx ctx; + struct verify v; + int ret; + + argc--; + argv++; + + ret = hx509_verify_init_ctx(&ctx); + ret = hx509_certs_init("MEMORY:anchors", 0, NULL, &anchors); + ret = hx509_certs_init("MEMORY:chain", 0, NULL, &chain); + ret = hx509_certs_init("MEMORY:certs", 0, NULL, &certs); + + if (argc < 1) + errx(1, "argc"); + + while(argc--) { + char *s = *argv++; + + if (strncmp(s, "chain:", 6) == 0) { + s += 6; + + ret = hx509_certs_append(chain, s); + if (ret) + errx(1, "hx509_certs_append: chain: %d", ret); + + } else if (strncmp(s, "anchor:", 7) == 0) { + s += 7; + + ret = hx509_certs_append(anchors, s); + if (ret) + errx(1, "hx509_certs_append: anchor: %d", ret); + + } else if (strncmp(s, "cert:", 5) == 0) { + s += 5; + + ret = hx509_certs_append(certs, s); + if (ret) + errx(1, "hx509_certs_append: certs: %d", ret); + + } else { + errx(1, "unknown option to verify: `%s'\n", s); + } + } + + hx509_verify_attach_anchors(ctx, anchors); + + v.ctx = ctx; + v.chain = chain; + + hx509_certs_iter(certs, verify_f, &v); + + hx509_certs_free(&anchors); + hx509_certs_free(&certs); + hx509_certs_free(&chain); + + return 0; +} + +static int +pcert_pkcs11(int argc, char **argv) +{ + int ret; + + argc--; + argv++; + + if (argc < 1) + errx(1, "argc"); + + ret = hx509_keyset_init(argv[0], NULL); + if (ret) { + printf("hx509_keyset_init: %d\n", ret); + return 0; + } + + return 0; +} + +static int help(int, char **); + +static SL_cmd cmds[] = { + { "cms-create-sd", + cms_create_sd, + "in-file out-file cert ...", + "create signed data" + }, + { "cms-verify-sd", + cms_verify_sd, + "file cert ...", + "verify signed data" + }, + { "cms-unenvelope", + cms_unenvelope, + "cert key in-file out-file", + "unenvelope data" + }, + { "cms-create-envelope", + cms_create_enveloped, + "cert in-file out-file", + "envelope data" + }, + + { "print", + pcert_print, + "cert ...", + "print certificates" + }, + { "validate", + pcert_validate, + "cert ...", + "validate certificates" + }, + { "verify", + pcert_verify, + "cert:foo chain:cert1 chain:cert2 anchor:anchor1 anchor:anchor2", + "verify certificates" + }, + { "pkcs11", + pcert_pkcs11, + "...", + "deal with pkcs11 devices" + }, + { "help", help, "help" }, + { "?" }, + { NULL } +}; + +int +help(int argc, char **argv) +{ + sl_help(cmds, argc, argv); + return 0; +} + +int +main(int argc, char **argv) +{ + int ret, optidx = 0; + + setprogname (argv[0]); + + if(getarg(args, num_args, argc, argv, &optidx)) + usage(1); + if(help_flag) + usage(0); + if(version_flag) { + print_version(NULL); + exit(0); + } + argv += optidx; + argc -= optidx; + + if (argc == 0) + usage(1); + + ret = sl_command(cmds, argc, argv); + if(ret == -1) + warnx ("unrecognized command: %s", argv[0]); + + return 0; +} diff --git a/lib/hx509/keyset.c b/lib/hx509/keyset.c new file mode 100644 index 000000000..73f5e351c --- /dev/null +++ b/lib/hx509/keyset.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2004 - 2005 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" +RCSID("$ID$"); + +static struct hx509_keyset_ops **ks_ops; +static int ks_num_ops; + +struct hx509_certs_data { + struct hx509_keyset_ops *ops; + void *ops_data; +}; + +static struct hx509_keyset_ops * +_hx509_ks_type(const char *type) +{ + int i; + + for (i = 0; i < ks_num_ops; i++) + if (strcasecmp(type, ks_ops[i]->name) == 0) + return ks_ops[i]; + + return NULL; +} + +void +_hx509_ks_register(struct hx509_keyset_ops *ops) +{ + struct hx509_keyset_ops **val; + + if (_hx509_ks_type(ops->name)) + return; + + val = realloc(ks_ops, (ks_num_ops + 1) * sizeof(ks_ops[0])); + if (val == NULL) + return; + val[ks_num_ops] = ops; + ks_ops = val; + ks_num_ops++; +} + +int +hx509_certs_init(const char *name, int flags, + hx509_lock lock, hx509_certs *certs) +{ + struct hx509_keyset_ops *ops; + const char *residue; + hx509_certs c; + char *type; + int ret; + + *certs = NULL; + + if (ks_ops == NULL) { + _hx509_ks_mem_register(); + _hx509_ks_file_register(); + _hx509_ks_pkcs12_register(); + } + + residue = strchr(name, ':'); + if (residue) { + type = strndup(name, residue - name); + residue++; + if (residue[0] == '\0') + residue = NULL; + } else { + type = strdup("MEMORY"); + residue = name; + } + if (type == NULL) + return ENOMEM; + + ops = _hx509_ks_type(type); + free(type); + if (ops == NULL) + return ENOENT; + + c = calloc(1, sizeof(*c)); + if (c == NULL) + return ENOMEM; + + c->ops = ops; + + ret = (*ops->init)(c, &c->ops_data, flags, residue, lock); + if (ret) { + free(c); + return ENOMEM; + } + + *certs = c; + return 0; +} + +void +hx509_certs_free(hx509_certs *certs) +{ + (*(*certs)->ops->free)(*certs, (*certs)->ops_data); + + free(*certs); + *certs = NULL; +} + +int +hx509_certs_start_seq(hx509_certs certs, hx509_cursor cursor) +{ + int ret; + + if (certs->ops->iter_start == NULL) + return ENOENT; + + ret = (*certs->ops->iter_start)(certs, certs->ops_data, cursor); + if (ret) + return ret; + + return 0; +} + +int +hx509_certs_next_cert(hx509_certs certs, hx509_cursor cursor, + hx509_cert *cert) +{ + *cert = NULL; + return (*certs->ops->iter)(certs, certs->ops_data, cursor, cert); +} + +int +hx509_certs_end_seq(hx509_certs certs, hx509_cursor cursor) +{ + (*certs->ops->iter_end)(certs, certs->ops_data, cursor); + return 0; +} + + +int +hx509_certs_iter(hx509_certs certs, int (*fn)(void *, hx509_cert), void *ctx) +{ + hx509_cursor cursor; + hx509_cert c; + int ret; + + ret = hx509_certs_start_seq(certs, &cursor); + if (ret) + return ret; + + while (1) { + ret = hx509_certs_next_cert(certs, cursor, &c); + if (ret) + break; + if (c == NULL) + break; + ret = (*fn)(ctx, c); + hx509_cert_free(c); + if (ret) + break; + } + + hx509_certs_end_seq(certs, cursor); + + return 0; +} + +int +hx509_ci_print_names(void *ctx, hx509_cert c) +{ + Certificate *cert; + hx509_name n; + char *str; + + cert = _hx509_get_cert(c); + + _hx509_name_from_Name(&cert->tbsCertificate.subject, &n); + hx509_name_to_string(n, &str); + hx509_name_free(&n); + fprintf(ctx, "%s\n", str); + free(str); + return 0; +} + +int +hx509_certs_add(hx509_certs certs, hx509_cert cert) +{ + if (certs->ops->add == NULL) + return ENOENT; + + return (*certs->ops->add)(certs, certs->ops_data, cert); +} + +int +_hx509_certs_find(hx509_certs certs, const hx509_query *q, hx509_cert *r) +{ + hx509_cursor cursor; + hx509_cert c; + int ret, found = 0; + + *r = NULL; + + if (certs->ops->query) + return (*certs->ops->query)(certs, certs->ops_data, q, r); + + ret = hx509_certs_start_seq(certs, &cursor); + if (ret) + return ret; + + while (1) { + ret = hx509_certs_next_cert(certs, cursor, &c); + if (ret) + break; + if (c == NULL) + break; + found = _hx509_query_match_cert(q, c); + if (found) { + *r = c; + break; + } + hx509_cert_free(c); + } + + hx509_certs_end_seq(certs, cursor); + + if (!found) + return ENOENT; + + return 0; +} + +static int +certs_merge_func(void *ctx, hx509_cert c) +{ + return hx509_certs_add((hx509_certs)ctx, c); +} + +int +hx509_certs_merge(hx509_certs to, hx509_certs from) +{ + return hx509_certs_iter(from, certs_merge_func, to); +} + +int +hx509_certs_append(hx509_certs to, const char *name) +{ + hx509_certs s; + int ret; + + ret = hx509_certs_init(name, 0, NULL, &s); + if (ret) + return ret; + ret = hx509_certs_merge(to, s); + hx509_certs_free(&s); + return ret; +} diff --git a/lib/hx509/ks_file.c b/lib/hx509/ks_file.c new file mode 100644 index 000000000..a46a58839 --- /dev/null +++ b/lib/hx509/ks_file.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2005 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" +RCSID("$ID$"); + +static int +parse_certificate(const char *fn, int use_pem, Certificate *t) +{ + char buf[1024]; + void *data = NULL; + size_t size, len = 0; + int in_cert = 0; + FILE *f; + int i, ret; + + memset(t, 0, sizeof(*t)); + + if ((f = fopen(fn, "r")) == NULL) + return ENOENT; + + if (use_pem) { + while (fgets(buf, sizeof(buf), f) != NULL) { + char *p; + + i = strcspn(buf, "\n"); + if (buf[i] == '\n') buf[i--] = '\0'; + if (buf[i] == '\r') buf[i--] = '\0'; + + if (i == 26 + && strcmp("-----BEGIN CERTIFICATE-----", buf) == 0) + { + in_cert = 1; + continue; + } else if (i == 24 && + strcmp("-----END CERTIFICATE-----", buf) == 0) + { + in_cert = 0; + continue; + } + if (in_cert == 0) + continue; + + p = malloc(i); + i = base64_decode(buf, p); + + data = erealloc(data, len + i); + memcpy(((char *)data) + len, p, i); + free(p); + len += i; + } + } else { + while((i = fread(buf, 1, sizeof(buf), f)) > 0) { + data = erealloc(data, len + i); + memcpy(((char *)data) + len, buf, i); + len += i; + } + } + + fclose(f); + + if (data == NULL) + return 1; + + if (data && in_cert) { + free(data); + return 1; + } + + ret = decode_Certificate(data, len, t, &size); + free(data); + if (ret != 0) { + return 1; + } + + return 0; +} + + +static int +file_init(hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + char *certfn, *keyfn, *friendlyname = NULL; + hx509_cert cert; + + *data = NULL; + + certfn = strdup(residue); + if (certfn == NULL) + return ENOMEM; + keyfn = strchr(certfn, ','); + if (keyfn) { + *keyfn++ = '\0'; + friendlyname = strchr(keyfn, ','); + if (friendlyname) + *friendlyname++ = '\0'; + } + + { + Certificate t; + int ret; + + ret = parse_certificate(certfn, 1, &t); + if (ret) + ret = parse_certificate(certfn, 0, &t); + if (ret) { + free(certfn); + return ret; + } + + ret = hx509_cert_init(&t, &cert); + free_Certificate(&t); + if (ret) { + free(certfn); + return ret; + } + } + + if (keyfn) { + int ret; + ret = _hx509_cert_assign_private_key_file(cert, lock, keyfn); + if (ret) { + hx509_cert_free(cert); + free(certfn); + return ret; + } + } + if (friendlyname) { + int ret; + ret = hx509_cert_set_friendly_name(cert, friendlyname); + if (ret) { + hx509_cert_free(cert); + free(certfn); + return ret; + } + } + free(certfn); + + *data = cert; + return 0; +} + +static int +file_free(hx509_certs certs, void *data) +{ + hx509_cert_free(data); + return 0; +} + + + +static int +file_iter_start(hx509_certs certs, void *data, void **cursor) +{ + int *i; + + i = malloc(sizeof(*i)); + if (i == NULL) + return ENOMEM; + *i = 0; + *cursor = i; + return 0; +} + +static int +file_iter(hx509_certs certs, void *data, void *iter, hx509_cert *cert) +{ + int *i = iter; + if (*i != 0) + return 0; + *cert = hx509_cert_ref((hx509_cert)data); + (*i)++; + return 0; +} + +static int +file_iter_end(hx509_certs certs, + void *data, + void *cursor) +{ + free(cursor); + return 0; +} + + +static struct hx509_keyset_ops keyset_file = { + "FILE", + 0, + file_init, + file_free, + NULL, + NULL, + file_iter_start, + file_iter, + file_iter_end +}; + +void +_hx509_ks_file_register(void) +{ + _hx509_ks_register(&keyset_file); +} diff --git a/lib/hx509/ks_mem.c b/lib/hx509/ks_mem.c new file mode 100644 index 000000000..1e455a5d9 --- /dev/null +++ b/lib/hx509/ks_mem.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2005 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" +RCSID("$ID$"); + +struct mem_data { + char *name; + unsigned long len; + hx509_cert *val; +}; + +static int +mem_init(hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + struct mem_data *mem; + mem = calloc(1, sizeof(*mem)); + if (mem == NULL) + return ENOMEM; + if (residue == NULL || residue[0] == '\0') + residue = "anonymous"; + mem->name = strdup(residue); + if (mem->name == NULL) { + free(mem); + return ENOMEM; + } + *data = mem; + return 0; +} + +static int +mem_free(hx509_certs certs, void *data) +{ + struct mem_data *mem = data; + unsigned long i; + + for (i = 0; i < mem->len; i++) + hx509_cert_free(mem->val[i]); + free(mem->val); + free(mem->name); + free(mem); + + return 0; +} + +static int +mem_add(hx509_certs certs, void *data, hx509_cert c) +{ + struct mem_data *mem = data; + hx509_cert *val; + + val = realloc(mem->val, (mem->len + 1) * sizeof(mem->val[0])); + if (val == NULL) + return ENOMEM; + + mem->val = val; + mem->val[mem->len] = hx509_cert_ref(c); + mem->len++; + + return 0; +} + +static int +mem_iter_start(hx509_certs certs, void *data, void **cursor) +{ + unsigned long *iter = malloc(sizeof(*iter)); + + if (iter == NULL) + return ENOMEM; + + *iter = 0; + *cursor = iter; + + return 0; +} + +static int +mem_iter(hx509_certs certs, + void *data, + void *cursor, + hx509_cert *cert) +{ + unsigned long *iter = cursor; + struct mem_data *mem = data; + + if (*iter >= mem->len) + return ENOENT; + + *cert = hx509_cert_ref(mem->val[*iter]); + (*iter)++; + return 0; +} + +static int +mem_iter_end(hx509_certs certs, + void *data, + void *cursor) +{ + free(cursor); + return 0; +} + +static struct hx509_keyset_ops keyset_mem = { + "MEMORY", + 0, + mem_init, + mem_free, + mem_add, + NULL, + mem_iter_start, + mem_iter, + mem_iter_end +}; + +void +_hx509_ks_mem_register(void) +{ + _hx509_ks_register(&keyset_mem); +} diff --git a/lib/hx509/ks_null.c b/lib/hx509/ks_null.c new file mode 100644 index 000000000..3f6a2242c --- /dev/null +++ b/lib/hx509/ks_null.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2005 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" +RCSID("$ID$"); + + +static int +null_init(hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + *data = NULL; + return 0; +} + +static int +null_free(hx509_certs certs, void *data) +{ + assert(data == NULL); + return 0; +} + +static int +null_iter_start(hx509_certs certs, void *data, void **cursor) +{ + *cursor = NULL; + return 0; +} + +static int +null_iter(hx509_certs certs, void *data, void *iter, hx509_cert *cert) +{ + *cert = NULL; + return ENOENT; +} + +static int +null_iter_end(hx509_certs certs, + void *data, + void *cursor) +{ + assert(cursor == NULL); + return 0; +} + + + + +struct hx509_keyset_ops keyset_null = { + "NULL", + 0, + null_init, + null_free, + NULL, + NULL, + null_iter_start, + null_iter, + null_iter_end +}; diff --git a/lib/hx509/ks_p12.c b/lib/hx509/ks_p12.c new file mode 100644 index 000000000..181bee56a --- /dev/null +++ b/lib/hx509/ks_p12.c @@ -0,0 +1,526 @@ +/* + * Copyright (c) 2004 - 2005 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" +RCSID("$Id$"); + +struct ks_pkcs12 { + hx509_certs certs; +}; + +struct private_key { + AlgorithmIdentifier alg; + heim_octet_string data; + heim_octet_string localKeyId; +}; + +struct collector { + hx509_lock lock; + hx509_certs unenvelop_certs; + hx509_certs certs; + struct { + struct private_key **data; + size_t len; + } val; +}; + +typedef int (*collector_func)(struct collector *, const void *, size_t, + const PKCS12_Attributes *); + +struct type { + const heim_oid * (*oid)(void); + collector_func func; +}; + +static int +parse_pkcs12_type(struct collector *, const heim_oid *, + const void *, size_t, const PKCS12_Attributes *); + + +static const PKCS12_Attribute * +find_attribute(const PKCS12_Attributes *attrs, const heim_oid *oid) +{ + int i; + if (attrs == NULL) + return NULL; + for (i = 0; i < attrs->len; i++) + if (heim_oid_cmp(oid, &attrs->val[i].attrId) == 0) + return &attrs->val[i]; + return NULL; +} + +static int +ShroudedKeyBag_parser(struct collector *c, const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + struct private_key *key; + const PKCS12_Attribute *attr; + PKCS8EncryptedPrivateKeyInfo pk; + PKCS8PrivateKeyInfo ki; + heim_octet_string content; + const struct _hx509_password *pw; + int i; + int ret; + + printf("pkcs8ShroudedKeyBag\n"); + memset(&pk, 0, sizeof(pk)); + + attr = find_attribute(attrs, oid_id_pkcs_9_at_localKeyId()); + if (attr == NULL) { + printf("no localKeyId, ignoreing private key\n"); + return 0; + } + + ret = decode_PKCS8EncryptedPrivateKeyInfo(data, length, &pk, NULL); + if (ret) { + printf("PKCS8EncryptedPrivateKeyInfo returned %d\n", ret); + return ret; + } + + pw = _hx509_lock_get_passwords(c->lock); + + ret = HX509_CRYPTO_INTERNAL_ERROR; + for (i = 0; i < pw->len; i++) { + ret = _hx509_pbe_decrypt(pw->val[i], + &pk.encryptionAlgorithm, + &pk.encryptedData, + &content); + if (ret == 0) + break; + } + free_PKCS8EncryptedPrivateKeyInfo(&pk); + if (ret) { + printf("decrypt encryped failed %d\n", ret); + return ret; + } + ret = decode_PKCS8PrivateKeyInfo(content.data, content.length, + &ki, NULL); + free_octet_string(&content); + if (ret) { + printf("PKCS8PrivateKeyInfo returned %d\n", ret); + return ret; + } + + key = malloc(sizeof(*key)); + if (key == NULL) { + free_PKCS8PrivateKeyInfo(&ki); + return ENOMEM; + } + + copy_AlgorithmIdentifier(&ki.privateKeyAlgorithm, &key->alg); + copy_octet_string(&ki.privateKey, &key->data); + copy_octet_string(&attr->attrValues, &key->localKeyId); + free_PKCS8PrivateKeyInfo(&ki); + + { + void *d; + d = realloc(c->val.data, (c->val.len + 1) * sizeof(c->val.data[0])); + if (d == NULL) { + abort(); + } + c->val.data = d; + c->val.data[c->val.len] = key; + c->val.len++; + } + return 0; +} + +static int +certBag_parser(struct collector *c, const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + heim_octet_string os; + Certificate t; + hx509_cert cert; + PKCS12_CertBag cb; + int ret; + + printf("certBag\n"); + + ret = decode_PKCS12_CertBag(data, length, &cb, NULL); + if (ret) + return ret; + + { + char *str; + hx509_oid_sprint(&cb.certType, &str); + printf("oid: %s\n", str); + } + + ret = decode_PKCS12_OctetString(cb.certValue.data, + cb.certValue.length, + &os, + NULL); + free_PKCS12_CertBag(&cb); + if (ret) { + printf("failed with %d\n", ret); + return 1; + } + + ret = decode_Certificate(os.data, os.length, &t, NULL); + free_octet_string(&os); + if (ret) { + printf("failed with %d\n", ret); + return 1; + } + printf("cert parsed ok\n"); + + ret = hx509_cert_init(&t, &cert); + free_Certificate(&t); + if (ret) { + return ret; + } + + ret = hx509_certs_add(c->certs, cert); + if (ret) { + hx509_cert_free(cert); + return ret; + } + + { + const PKCS12_Attribute *attr; + const heim_oid * (*oids[])(void) = { + oid_id_pkcs_9_at_localKeyId, oid_id_pkcs_9_at_friendlyName + }; + int i; + + for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) { + const heim_oid *oid = (*(oids[i]))(); + attr = find_attribute(attrs, oid); + if (attr) + _hx509_set_cert_attribute(cert, oid, &attr->attrValues); + } + } + { + const char *s = hx509_cert_get_friendly_name(cert); + printf("cert name: %s\n", s ? s : "no name set"); + } + + return 0; +} + +static int +parse_safe_content(struct collector *c, const unsigned char *p, size_t len) +{ + PKCS12_SafeContents sc; + int ret, i; + + memset(&sc, 0, sizeof(sc)); + + ret = decode_PKCS12_SafeContents(p, len, &sc, NULL); + if (ret) + return ret; + + for (i = 0; i < sc.len ; i++) + parse_pkcs12_type(c, + &sc.val[i].bagId, + sc.val[i].bagValue.data, + sc.val[i].bagValue.length, + sc.val[i].bagAttributes); + + free_PKCS12_SafeContents(&sc); + return 0; +} + +static int +safeContent_parser(struct collector *c, const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + heim_octet_string os; + int ret; + + printf("safeContent\n"); + + ret = decode_PKCS12_OctetString(data, length, &os, NULL); + if (ret) + return 1; + ret = parse_safe_content(c, os.data, os.length); + free_octet_string(&os); + return ret; +}; + +static int +encryptedData_parser(struct collector *c, const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + heim_octet_string content; + heim_oid contentType; + int ret; + + memset(&contentType, 0, sizeof(contentType)); + + ret = hx509_cms_decrypt_encrypted(c->lock, + data, length, + &contentType, + &content); + if (ret) + printf("decrypt encryped failed %d\n", ret); + else { + if (content.length == 0) { + printf("no content in encryped data\n"); + } else if (heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0) { + ret = parse_safe_content(c, content.data, content.length); + if (ret) + printf("parse_safe_content failed with %d\n", ret); + } + } + + return 0; +} + +static int +envelopedData_parser(struct collector *c, const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + heim_octet_string content; + heim_oid contentType; + int ret; + + memset(&contentType, 0, sizeof(contentType)); + + ret = hx509_cms_unenvelope(c->unenvelop_certs, + data, length, + &contentType, + &content); + if (ret) + printf("unenveloped failed %d\n", ret); + else { + if (content.length == 0) { + printf("no content enveloped data\n"); + } else if (heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0) { + ret = parse_safe_content(c, content.data, content.length); + if (ret) + printf("parse_safe_content failed with %d\n", ret); + } + } + + return 0; +} + + +struct type bagtypes[] = { + { oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser }, + { oid_id_pkcs12_certBag, certBag_parser }, + { oid_id_pkcs7_data, safeContent_parser }, + { oid_id_pkcs7_encryptedData, encryptedData_parser }, + { oid_id_pkcs7_envelopedData, envelopedData_parser } +}; + +static int +parse_pkcs12_type(struct collector *c, const heim_oid *oid, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + int i; + + for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++) { + if (heim_oid_cmp((*bagtypes[i].oid)(), oid) == 0) { + (*bagtypes[i].func)(c, data, length, attrs); + return 0; + } + } + return 1; +} + +static int +p12_init(hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + size_t len; + void *buf; + PKCS12_PFX pfx; + PKCS12_AuthenticatedSafe as; + int ret, i; + struct collector c; + + *data = NULL; + + if (lock == NULL) + lock = _hx509_empty_lock; + + ret = _hx509_map_file(residue, &buf, &len); + if (ret) + return ret; + + ret = decode_PKCS12_PFX(buf, len, &pfx, NULL); + _hx509_unmap_file(buf, len); + if (ret) + return ret; + + if (heim_oid_cmp(&pfx.authSafe.contentType, oid_id_pkcs7_data()) != 0) { + free_PKCS12_PFX(&pfx); + ret = EINVAL; + goto out; + } + + if (pfx.authSafe.content == NULL) { + free_PKCS12_PFX(&pfx); + ret = EINVAL; + goto out; + } + + { + heim_octet_string asdata; + + ret = decode_PKCS12_OctetString(pfx.authSafe.content->data, + pfx.authSafe.content->length, + &asdata, + NULL); + free_PKCS12_PFX(&pfx); + if (ret) + goto out; + ret = decode_PKCS12_AuthenticatedSafe(asdata.data, + asdata.length, + &as, + NULL); + free_octet_string(&asdata); + if (ret) + goto out; + } + + c.lock = lock; + hx509_certs_init("MEMORY:dummy", 0, NULL, &c.unenvelop_certs); + c.val.data = NULL; + c.val.len = 0; + hx509_certs_init("MEMORY:pkcs12-store", 0, NULL, &c.certs); + + for (i = 0; i < as.len; i++) { + parse_pkcs12_type(&c, + &as.val[i].contentType, + as.val[i].content->data, + as.val[i].content->length, + NULL); + } + + free_PKCS12_AuthenticatedSafe(&as); + + printf("found %d private keys\n", c.val.len); + + for (i = 0; i < c.val.len; i++) { + hx509_cert cert; + hx509_query q; + + _hx509_query_clear(&q); + q.match |= HX509_QUERY_MATCH_LOCAL_KEY_ID; + + q.local_key_id = &c.val.data[i]->localKeyId; + + ret = _hx509_certs_find(c.certs, &q, &cert); + if (ret == 0) { + hx509_private_key key; + + ret = _hx509_parse_private_key(&c.val.data[i]->alg.algorithm, + c.val.data[i]->data.data, + c.val.data[i]->data.length, + &key); + if (ret == 0) + _hx509_cert_assign_key(cert, key); + else + printf("failed to parse key: %d\n", ret); + + hx509_cert_free(cert); + } + free_octet_string(&c.val.data[i]->localKeyId); + free_octet_string(&c.val.data[i]->data); + free_AlgorithmIdentifier(&c.val.data[i]->alg); + free(c.val.data[i]); + } + free(c.val.data); + + { + struct ks_pkcs12 *p12; + p12 = malloc(sizeof(*p12)); + if (p12 == NULL) { + abort(); + } + memset(p12, 0, sizeof(*p12)); + p12->certs = c.certs; + *data = p12; + } + ret = 0; + out: + return ret; +} + +static int +p12_free(hx509_certs certs, void *data) +{ + struct ks_pkcs12 *p12 = data; + hx509_certs_free(&p12->certs); + free(p12); + return 0; +} + +static int +p12_iter_start(hx509_certs certs, void *data, void **cursor) +{ + struct ks_pkcs12 *p12 = data; + return hx509_certs_start_seq(p12->certs, cursor); +} + +static int +p12_iter(hx509_certs certs, void *data, void *cursor, hx509_cert *cert) +{ + struct ks_pkcs12 *p12 = data; + return hx509_certs_next_cert(p12->certs, cursor, cert); +} + +static int +p12_iter_end(hx509_certs certs, + void *data, + void *cursor) +{ + struct ks_pkcs12 *p12 = data; + return hx509_certs_end_seq(p12->certs, cursor); +} + + + + +static struct hx509_keyset_ops keyset_pkcs12 = { + "PKCS12", + 0, + p12_init, + p12_free, + NULL, + NULL, + p12_iter_start, + p12_iter, + p12_iter_end +}; + +void +_hx509_ks_pkcs12_register(void) +{ + _hx509_ks_register(&keyset_pkcs12); +} diff --git a/lib/hx509/lock.c b/lib/hx509/lock.c new file mode 100644 index 000000000..65ed0c2f9 --- /dev/null +++ b/lib/hx509/lock.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2005 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" +RCSID("$ID$"); + +struct hx509_lock_data { + struct _hx509_password password; + hx509_certs certs; + hx509_prompter_fct *prompt; + void *prompt_data; +}; + +static struct hx509_lock_data empty_lock_data = { + { 0, NULL } +}; + +hx509_lock _hx509_empty_lock = &empty_lock_data; + +/* + * + */ + +int +hx509_lock_init(hx509_lock *lock) +{ + hx509_lock l; + int ret; + + *lock = NULL; + + l = calloc(1, sizeof(*l)); + if (l == NULL) + return ENOMEM; + + ret = hx509_certs_init("MEMORY:locks-internal", 0, NULL, &l->certs); + if (ret) { + free(l); + return ret; + } + + *lock = l; + + return 0; +} + +int +hx509_lock_add_password(hx509_lock lock, const char *password) +{ + void *d; + char *s; + + s = strdup(password); + if (s == NULL) + return ENOMEM; + + d = realloc(lock->password.val, + (lock->password.len + 1) * sizeof(lock->password.val[0])); + if (d == NULL) { + free(s); + return ENOMEM; + } + lock->password.val = d; + lock->password.val[lock->password.len] = s; + lock->password.len++; + + return 0; +} + +const struct _hx509_password * +_hx509_lock_get_passwords(hx509_lock lock) +{ + return &lock->password; +} + +void +hx509_lock_reset_passwords(hx509_lock lock) +{ + int i; + for (i = 0; i < lock->password.len; i++) + free(lock->password.val[i]); + free(lock->password.val); + lock->password.val = NULL; + lock->password.len = 0; +} + +int +hx509_lock_add_cert(hx509_lock lock, hx509_cert cert) +{ + return hx509_certs_add(lock->certs, cert); +} + +int +hx509_lock_add_certs(hx509_lock lock, hx509_certs certs) +{ + return hx509_certs_merge(lock->certs, certs); +} + +void +hx509_lock_reset_certs(hx509_lock lock) +{ + hx509_certs certs = lock->certs; + int ret; + + ret = hx509_certs_init("MEMORY:locks-internal", 0, NULL, &lock->certs); + if (ret == 0) + hx509_certs_free(&certs); + else + lock->certs = certs; +} + +int +_hx509_lock_find_cert(hx509_lock lock, const hx509_query *q, hx509_cert *c) +{ + *c = NULL; + return 0; +} + +int +hx509_lock_set_prompter(hx509_lock lock, hx509_prompter_fct *prompt) +{ + lock->prompt = prompt; + return 0; +} + +int +hx509_lock_set_prompter_data(hx509_lock lock, void *data) +{ + lock->prompt_data = data; + return 0; +} + +void +hx509_lock_reset_promper(hx509_lock lock) +{ + lock->prompt = NULL; + lock->prompt_data = NULL; +} + +int +hx509_lock_prompt(hx509_lock lock, hx509_prompt *prompt) +{ + if (lock->prompt == NULL) { + strlcpy(prompt->reply->data, "", prompt->reply->length); + return 0; + } + return (*lock->prompt)(lock->prompt_data, prompt); +} + +void +hx509_lock_free(hx509_lock lock) +{ + hx509_certs_free(&lock->certs); + hx509_lock_reset_passwords(lock); + memset(lock, 0, sizeof(*lock)); + free(lock); +} diff --git a/lib/hx509/name.c b/lib/hx509/name.c new file mode 100644 index 000000000..466d3971b --- /dev/null +++ b/lib/hx509/name.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2004 - 2005 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" +RCSID("$ID$"); + +/* + * name parsing from rfc2253 + * fix so parsing rfc1779 works too + * rfc3280 + */ + +#define oid_enc(n) { sizeof(n)/sizeof(n[0]), n } + +static unsigned country_num[] = { 2, 5, 4, 6 }; +static heim_oid country_oid = oid_enc(country_num); +static unsigned organizationName_num[] = { 2, 5, 4, 10 }; +static heim_oid organizationName_oid = oid_enc(organizationName_num); +static unsigned commonName_num[] = { 2, 5, 4, 3 }; +static heim_oid commonName_oid = oid_enc(commonName_num); +static unsigned localityName_num[] = { 2, 5, 4, 7 }; +static heim_oid localityName_oid = oid_enc(localityName_num); +static unsigned email_num[] = { 1, 2, 840, 113549, 1, 9, 1 }; +static heim_oid email_oid = oid_enc(email_num); +static unsigned uid_num[] = { 0, 9, 2342, 19200300, 100, 1, 1 }; +static heim_oid uid_oid = oid_enc(uid_num); + +static const struct { + char *n; + heim_oid *o; +} no[] = { + { "C", &country_oid }, + { "CN", &commonName_oid }, + { "O", &organizationName_oid }, + { "L", &localityName_oid }, + { "Email", &email_oid }, + { "UID", &uid_oid } +}; + +static char * +quote_string(const char *f, size_t len, size_t *rlen) +{ + size_t i, j, tolen; + const unsigned char *from = f; + unsigned char *to; + + tolen = len * 3 + 1; + to = malloc(tolen); + if (to == NULL) + return NULL; + + for (i = 0, j = 0; i < len; i++) { + if (from[i] == ' ' && i + 1 < len) + to[j++] = from[i]; + else if (from[i] == ',' || from[i] == '=' || from[i] == '+' || + from[i] == '<' || from[i] == '>' || from[i] == '#' || + from[i] == ';' || from[i] == ' ') + { + to[j++] = '\\'; + to[j++] = from[i]; + } else if (from[i] >= 32 && from[i] <= 127) { + to[j++] = from[i]; + } else { + int l = snprintf(&to[j], tolen - j - 1, + "#%02x", (unsigned int)from[i]); + j += l; + } + } + to[j] = '\0'; + *rlen = j; + return to; +} + + +static int +append_string(char **str, size_t *total_len, char *ss, size_t len, int quote) +{ + char *s, *qs; + + if (quote) + qs = quote_string(ss, len, &len); + else + qs = ss; + + s = realloc(*str, len + *total_len + 1); + if (s == NULL) + abort(); + memcpy(s + *total_len, qs, len); + if (qs != ss) + free(qs); + s[*total_len + len] = '\0'; + *str = s; + *total_len += len; + return 0; +} + +static char * +oidtostring(const heim_oid *type) +{ + char *s = NULL, *ss; + size_t i, total_len = 0; + + for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) { + if (heim_oid_cmp(no[i].o, type) == 0) + return strdup(no[i].n); + } + + for (i = 0; i < type->length; i++) { + asprintf(&ss, "%u", type->components[i]); + append_string(&s, &total_len, ss, strlen(ss), 0); + if (i + 1 < type->length) + append_string(&s, &total_len, ".", 1, 0); + } + return s; +} + +int +hx509_name_to_string(const hx509_name name, char **str) +{ + const Name *n = &name->der_name; + ssize_t total_len = 0; + int i, j; + + *str = strdup(""); + if (*str == NULL) + return ENOMEM; + + for (i = 0 ; i < n->u.rdnSequence.len; i++) { + char *ss; + int len; + + for (j = 0; j < n->u.rdnSequence.val[i].len; j++) { + DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value; + char *oidname; + + oidname = oidtostring(&n->u.rdnSequence.val[i].val[j].type); + + switch(ds->element) { + case choice_DirectoryString_ia5String: + ss = ds->u.ia5String; + break; + case choice_DirectoryString_printableString: + ss = ds->u.ia5String; + break; + case choice_DirectoryString_utf8String: + ss = ds->u.ia5String; + break; +#if 0 + case choice_DirectoryString_bmpstring: + ss = ds->u.bmpstring; + break; +#endif + default: + abort(); + } + append_string(str, &total_len, oidname, strlen(oidname), 0); + free(oidname); + append_string(str, &total_len, "=", 1, 0); + len = strlen(ss); + append_string(str, &total_len, ss, len, 1); + if (j + 1 < n->u.rdnSequence.val[i].len) + append_string(str, &total_len, "+", 1, 0); + } + + if (i + 1 < n->u.rdnSequence.len) + append_string(str, &total_len, ", ", 2, 0); + } + return 0; +} + +/* + * XXX this function is broken, it needs to compare code points, not + * bytes. + */ + +int +_hx509_name_ds_cmp(const DirectoryString *ds1, const DirectoryString *ds2) +{ + int c; + + c = ds1->element - ds2->element; + if (c) + return c; + + switch(ds1->element) { + case choice_DirectoryString_ia5String: + c = strcmp(ds1->u.ia5String, ds2->u.ia5String); + break; + case choice_DirectoryString_teletexString: + c = heim_octet_string_cmp(&ds1->u.teletexString, + &ds2->u.teletexString); + break; + case choice_DirectoryString_printableString: + c = strcmp(ds1->u.printableString, ds2->u.printableString); + break; + case choice_DirectoryString_utf8String: + c = strcmp(ds1->u.utf8String, ds2->u.utf8String); + break; + case choice_DirectoryString_universalString: + c = heim_universal_string_cmp(&ds1->u.universalString, + &ds2->u.universalString); + break; + case choice_DirectoryString_bmpString: + c = heim_bmp_string_cmp(&ds1->u.bmpString, + &ds2->u.bmpString); + break; + default: + return 1; + } + return 0; +} + +int +_hx509_name_cmp(const Name *n1, const Name *n2) +{ + int i, j, c; + + c = n1->u.rdnSequence.len - n2->u.rdnSequence.len; + if (c) + return c; + + for (i = 0 ; i < n1->u.rdnSequence.len; i++) { + c = n1->u.rdnSequence.val[i].len - n2->u.rdnSequence.val[i].len; + if (c) + return c; + + for (j = 0; j < n1->u.rdnSequence.val[i].len; j++) { + c = heim_oid_cmp(&n1->u.rdnSequence.val[i].val[j].type, + &n1->u.rdnSequence.val[i].val[j].type); + if (c) + return c; + + c = _hx509_name_ds_cmp(&n1->u.rdnSequence.val[i].val[j].value, + &n2->u.rdnSequence.val[i].val[j].value); + if (c) + return c; + } + } + return 0; +} + +int +_hx509_name_from_Name(const Name *n, hx509_name *name) +{ + int ret; + *name = calloc(1, sizeof(**name)); + if (*name == NULL) + return ENOMEM; + ret = copy_Name(n, &(*name)->der_name); + if (ret) { + free(*name); + *name = NULL; + } + return ret; +} + +static int +hx509_der_parse_name(const void *data, size_t length, hx509_name *name) +{ + int ret; + Name n; + + *name = NULL; + ret = decode_Name(data, length, &n, NULL); + if (ret) + return ret; + return _hx509_name_from_Name(&n, name); +} + +void +hx509_name_free(hx509_name *name) +{ + free_Name(&(*name)->der_name); + memset(*name, 0, sizeof(**name)); + free(*name); + *name = NULL; +} + +int +hx509_parse_name(const void *data, size_t length, char **str) +{ + hx509_name name; + int ret; + + ret = hx509_der_parse_name(data, length, &name); + if (ret) + return ret; + + ret = hx509_name_to_string(name, str); + hx509_name_free(&name); + return ret; +} diff --git a/lib/hx509/p11.c b/lib/hx509/p11.c new file mode 100644 index 000000000..f7a2c09b9 --- /dev/null +++ b/lib/hx509/p11.c @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2004 - 2005 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" +RCSID("$ID$"); + +/* http://developer.netscape.com/support/faqs/pkcs_11.html */ + +#include + +#include + +#include "pkcs11u.h" +#include "pkcs11.h" + +typedef struct hx509_security_device_data *hx509_security_device; +typedef struct hx509_keyset_data *hx509_keyset; + +struct p11_slot { + int flags; +#define P11_SESSION 1 +#define P11_LOGIN_REQ 2 +#define P11_LOGIN_DONE 4 + CK_SESSION_HANDLE session; + CK_SLOT_ID id; + CK_BBOOL token; + char *name; + char *pin; +}; + +struct hx509_security_device_data { + int refcount; + void *handle; + CK_FUNCTION_LIST_PTR funcs; + CK_ULONG num_slots; + struct p11_slot *slots; + int selected_slot; /* XXX */ +}; + +#define P11SESSION(module) ((module)->slots[(module)->selected_slot].session) +#define P11FUNC(module,f,args) (*(module)->funcs->C_##f)args + +struct hx509_keyset_data { + hx509_security_device device; + hx509_certs certs; +}; + + +typedef struct hx509_key_data *hx509_key; + +static int +hx509_p11_load_module(const char *fn, hx509_security_device *module) +{ + CK_C_GetFunctionList getFuncs; + hx509_security_device p; + int ret; + + *module = NULL; + + p = calloc(1, sizeof(*p)); + if (p == NULL) + return ENOMEM; + + p->selected_slot = 0; + + p->handle = dlopen(fn, RTLD_NOW); + if (p->handle == NULL) { + ret = EINVAL; /* XXX */ + goto out; + } + + getFuncs = dlsym(p->handle, "C_GetFunctionList"); + if (getFuncs == NULL) { + ret = EINVAL; + goto out; + } + + ret = (*getFuncs)(&p->funcs); + if (ret) { + ret = EINVAL; + goto out; + } + + ret = P11FUNC(p, Initialize, (NULL_PTR)); + if (ret != CKR_OK) { + ret = EINVAL; + goto out; + } + + { + CK_INFO info; + + ret = P11FUNC(p, GetInfo, (&info)); + if (ret != CKR_OK) { + ret = EINVAL; + goto out; + } + + printf("module information:\n"); + printf("version: %04x.%04x\n", + (unsigned int)info.cryptokiVersion.major, + (unsigned int)info.cryptokiVersion.minor); + printf("manufacturer: %.*s\n", + (int)sizeof(info.manufacturerID) - 1, + info.manufacturerID); + printf("flags: 0x%04x\n", (unsigned int)info.flags); + printf("library description: %.*s\n", + (int)sizeof(info.libraryDescription) - 1, + info.libraryDescription); + printf("version: %04x.%04x\n", + (unsigned int)info.libraryVersion.major, + (unsigned int)info.libraryVersion.minor); + + } + + ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots)); + if (ret) { + ret = EINVAL; + goto out; + } + + printf("num slots: %ld\n", (long)p->num_slots); + + { + CK_SLOT_ID_PTR slot_ids; + int i, j; + + slot_ids = malloc(p->num_slots * sizeof(*slot_ids)); + if (slot_ids == NULL) { + ret = ENOMEM; + goto out; + } + + ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots)); + if (ret) { + free(slot_ids); + ret = EINVAL; + goto out; + } + + p->slots = calloc(p->num_slots, sizeof(p->slots[0])); + if (p->slots == NULL) { + free(slot_ids); + ret = ENOMEM; + goto out; + } + + for (i = 0; i < p->num_slots; i++) { + CK_SLOT_INFO slot_info; + CK_TOKEN_INFO token_info; + + printf("slot %d = id %d\n", i, (int)slot_ids[i]); + + p->slots[i].id = slot_ids[i]; + + ret = P11FUNC(p, GetSlotInfo, (slot_ids[i], &slot_info)); + if (ret) + continue; + + for (j = sizeof(slot_info.slotDescription) - 1; j > 0; j--) { + char c = slot_info.slotDescription[j]; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0') + continue; + j++; + break; + } + + asprintf(&p->slots[i].name, "%.*s (slot %d)", + j, slot_info.slotDescription, i); + + printf("description: %s\n", p->slots[i].name); + + printf("manufacturer: %.*s\n", + (int)sizeof(slot_info.manufacturerID), + slot_info.manufacturerID); + + if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0) { + printf("no token present\n"); + continue; + } + + ret = P11FUNC(p, GetTokenInfo, (slot_ids[i], &token_info)); + if (ret) + continue; + + printf("token present\n"); + + printf("label: %.*s\n", + (int)sizeof(token_info.label), + token_info.label); + printf("manufacturer: %.*s\n", + (int)sizeof(token_info.manufacturerID), + token_info.manufacturerID); + printf("model: %.*s\n", + (int)sizeof(token_info.model), + token_info.model); + printf("serialNumber: %.*s\n", + (int)sizeof(token_info.serialNumber), + token_info.serialNumber); + + printf("flags: 0x%04x\n", (unsigned int)token_info.flags); + + printf("slotinfo.flags 0x%x & 0x%x = 0x%x\n", + (int)slot_info.flags, (int)CKF_LOGIN_REQUIRED, + (int)(slot_info.flags & CKF_LOGIN_REQUIRED)); + if (token_info.flags & CKF_LOGIN_REQUIRED) { + printf("login required\n"); + p->slots[i].flags |= P11_LOGIN_REQ; + } + } + } + + *module = p; + + return 0; + out: + if (p->slots) + free(p->slots); + if (p->handle) + dlclose(p->handle); + free(p); + return ret; + +} + +static int +p11_get_session(hx509_security_device module, const char *conf, int slot) +{ + CK_RV ret; + + module->selected_slot = slot; + + if (slot >= module->num_slots) + return EINVAL; + + if (module->slots[slot].flags & P11_SESSION) + return EINVAL; /* XXX */ + + ret = P11FUNC(module, OpenSession, (module->slots[slot].id, + CKF_SERIAL_SESSION, + NULL, + NULL, + &module->slots[slot].session)); + if (ret != CKR_OK) + return EINVAL; + + module->slots[slot].flags |= P11_SESSION; + + if ((module->slots[slot].flags & P11_LOGIN_REQ) && + (module->slots[slot].flags & P11_LOGIN_DONE) == 0) { + char pin[20]; + char *prompt; + + module->slots[slot].flags |= P11_LOGIN_DONE; + + asprintf(&prompt, "PIN code for %s: ", module->slots[slot].name); + + if (UI_UTIL_read_pw_string(pin, sizeof(pin), prompt, 0)) { + printf("no pin"); + goto out; + } + free(prompt); + + ret = P11FUNC(module, Login, + (P11SESSION(module), CKU_USER, "3962", 4)); + if (ret != CKR_OK) + printf("login failed\n"); + else + module->slots[slot].pin = strdup(pin); + out:; + } + + return 0; +} + +static int +p11_put_session(hx509_security_device module, int slot) +{ + int ret; + + if (module->slots[slot].flags & P11_SESSION) + return EINVAL; + ret = P11FUNC(module, CloseSession, (module->slots[slot].session)); + if (ret != CKR_OK) + return EINVAL; + + return 0; +} + + +static int +iterate_entries(hx509_security_device module, hx509_certs ks, + CK_ATTRIBUTE *search_data, int num_search_data, + CK_ATTRIBUTE *query, int num_query, + int (*func)(void *, CK_ATTRIBUTE *, int), void *ptr) +{ + CK_OBJECT_HANDLE object; + CK_ULONG object_count; + int ret, i; + + printf("current slot: %d\n", module->selected_slot); + + ret = P11FUNC(module, FindObjectsInit, + (P11SESSION(module), search_data, num_search_data)); + if (ret != CKR_OK) { + return -1; + } + while (1) { + ret = P11FUNC(module, FindObjects, + (P11SESSION(module), &object, 1, &object_count)); + if (ret != CKR_OK) { + return -1; + } + printf("object count = %d\n", (int)object_count); + if (object_count == 0) + break; + + for (i = 0; i < num_query; i++) + query[i].pValue = NULL; + + ret = P11FUNC(module, GetAttributeValue, + (P11SESSION(module), object, query, num_query)); + if (ret != CKR_OK) { + return -1; + } + for (i = 0; i < num_query; i++) { + printf("id %d len = %d\n", i, (int)query[i].ulValueLen); + query[i].pValue = malloc(query[i].ulValueLen); + if (query[i].pValue == NULL) { + ret = ENOMEM; + goto out; + } + } + ret = P11FUNC(module, GetAttributeValue, + (P11SESSION(module), object, query, num_query)); + if (ret != CKR_OK) { + ret = -1; + goto out; + } + + ret = (*func)(ptr, query, num_query); + if (ret) + goto out; + + for (i = 0; i < num_query; i++) { + if (query[i].pValue) + free(query[i].pValue); + query[i].pValue = NULL; + } + } + out: + + for (i = 0; i < num_query; i++) { + if (query[i].pValue) + free(query[i].pValue); + query[i].pValue = NULL; + } + + ret = P11FUNC(module, FindObjectsFinal, (P11SESSION(module))); + if (ret != CKR_OK) { + return -2; + } + + + return 0; +} + +static int +print_id(void *ptr, CK_ATTRIBUTE *query, int num_query) +{ + printf("id: %.*s\n", (int)query[0].ulValueLen, (char *)query[0].pValue); + return 0; +} + +static int +print_cert(void *ptr, CK_ATTRIBUTE *query, int num_query) +{ + hx509_validate_ctx ctx; + hx509_cert cert; + Certificate c; + int ret; + + printf("id: %d\n", (int)query[0].ulValueLen); + + memset(&c, 0, sizeof(c)); + ret = decode_Certificate(query[1].pValue, query[1].ulValueLen, + &c, NULL); + if (ret) { + printf("decode_Certificate failed with %d\n", ret); + return 0; + } + + ret = hx509_cert_init(&c, &cert); + if (ret) + abort(); + free_Certificate(&c); + + hx509_validate_ctx_init(&ctx); + hx509_validate_ctx_set_print(ctx, hx509_print_stdout, stdout); + hx509_validate_ctx_add_flags(ctx, HX509_VALIDATE_F_VERBOSE); + + hx509_validate_cert(ctx, cert); + + hx509_validate_ctx_free(ctx); + hx509_cert_free(cert); + + return 0; +} + + +static int +p11_list_keys(hx509_security_device module, hx509_certs ks) +{ + CK_OBJECT_CLASS key_class; + CK_ATTRIBUTE search_data[] = { + {CKA_CLASS, &key_class, sizeof(key_class)}, + }; + CK_ATTRIBUTE query_data[2] = { + {CKA_ID, NULL, 0}, + {CKA_VALUE, NULL, 0} + }; + int ret; + + printf("---- private\n"); + key_class = CKO_PRIVATE_KEY; + ret = iterate_entries(module, ks, search_data, 1, + query_data, 1, + print_id, NULL); + if (ret) { + return ret; + } + + printf("---- public\n"); + key_class = CKO_PUBLIC_KEY; + ret = iterate_entries(module, ks, search_data, 1, + query_data, 1, + print_id, NULL); + if (ret) { + return ret; + } + + printf("---- cert\n"); + key_class = CKO_CERTIFICATE; + ret = iterate_entries(module, ks, search_data, 1, + query_data, 2, + print_cert, NULL); + if (ret) { + return ret; + } + printf("----\n"); + + + return 0; +} + +static int +security_device_add(hx509_security_device *device, const char *conf) +{ + hx509_security_device module; + char *c, *fn; + int ret; + + *device = NULL; + + c = strdup(conf); + if (c == NULL) + return ENOMEM; + + fn = strchr(c, ':'); + if (fn) + *fn++ = '\0'; + else + fn = "/usr/lib/default-pkcs11.so"; + + if (strcasecmp(c, "PKCS11") != 0) { + free(c); + return EINVAL; + } + + ret = hx509_p11_load_module(fn, &module); + free(c); + if (ret) + return ret; + + *device = module; + return 0; +} + + +int +hx509_keyset_init(const char *file, const char *conf) +{ + hx509_security_device module; + hx509_keyset ks; + int ret, slot; + + ret = security_device_add(&module, file); + if (ret) { + printf("security_device_add: %d\n", ret); + return 0; + } + + module->refcount++; + + ks = calloc(1, sizeof(*ks)); + if (ks == NULL) + return ENOMEM; + + ks->device = module; + + ret = hx509_certs_init("MEMORY:pkcs-11-store", 0, NULL, &ks->certs); + if (ret) + goto out; + + /* + * XXX just check if the device change changed, and if that case + * refresh contents of cache + */ + + slot = 0; + + ret = p11_get_session(module, conf, slot); + if (ret) + goto out; + + /* fetch certificates and keys */ + ret = p11_list_keys(module, ks->certs); + if (ret) + goto out_session; + + out_session: + + ret = p11_put_session(module, slot); + + out: + if (ret) { + hx509_certs_free(&ks->certs); + memset(ks, 0, sizeof(ks)); + free(ks); + module->refcount--; + } else { + hx509_certs_iter(ks->certs, hx509_ci_print_names, stdout); + } + + return 0; +} diff --git a/lib/hx509/print.c b/lib/hx509/print.c new file mode 100644 index 000000000..f9ca59d5b --- /dev/null +++ b/lib/hx509/print.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2004 - 2005 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" +RCSID("$ID$"); + + +struct hx509_validate_ctx_data { + int flags; + hx509_vprint_func vprint_func; + void *ctx; +}; + +/* + * + */ + +static int +Time2string(const Time *T, char **str) +{ + time_t t; + char *s; + struct tm *tm; + + *str = NULL; + t = _hx509_Time2time_t(T); + tm = gmtime (&t); + s = malloc(30); + if (s == NULL) + return ENOMEM; + strftime(s, 30, "%Y-%m-%d %M:%M:%S", tm); + *str = s; + return 0; +} + +void +hx509_print_stdout(void *ctx, const char *fmt, va_list va) +{ + FILE *f = ctx; + vfprintf(f, fmt, va); +} + +void +hx509_print_func(hx509_vprint_func func, void *ctx, const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + (*func)(ctx, fmt, va); + va_end(va); +} + +int +hx509_oid_sprint(const heim_oid *oid, char **str) +{ + char *s, *r; + int i; + s = strdup(""); + for (i = 0; i < oid->length; i++) { + asprintf(&r, "%s%d%s", s, oid->components[i], + i < oid->length - 1 ? "." : ""); + free(s); + s = r; + } + *str = s; + return 0; +} + +void +hx509_oid_print(const heim_oid *oid, hx509_vprint_func func, void *ctx) +{ + char *str; + hx509_oid_sprint(oid, &str); + hx509_print_func(func, ctx, "%s", str); + free(str); +} + +void +hx509_bitstring_print(const heim_bit_string *b, + hx509_vprint_func func, void *ctx) +{ + int i; + hx509_print_func(func, ctx, "\tlength: %d\n\t", b->length); + for (i = 0; i < (b->length + 7) / 8; i++) + hx509_print_func(func, ctx, "%02x%s%s", + ((unsigned char *)b->data)[i], + i < (b->length - 7) / 8 + && (i == 0 || (i % 16) != 15) ? ":" : "", + i != 0 && (i % 16) == 15 ? + (i <= ((b->length + 7) / 8 - 2) ? "\n\t" : "\n"):""); +} + +/* + * + */ + +static void +validate_vprint(void *c, const char *fmt, va_list va) +{ + hx509_validate_ctx ctx = c; + if (ctx->vprint_func == NULL) + return; + (ctx->vprint_func)(ctx->ctx, fmt, va); +} + +static void +validate_print(hx509_validate_ctx ctx, int flags, const char *fmt, ...) +{ + va_list va; + if ((ctx->flags & flags) == 0) + return; + va_start(va, fmt); + validate_vprint(ctx, fmt, va); + va_end(va); +} + +enum critical_flag { D_C = 0, S_C, S_N_C, M_C, M_N_C }; + +static int +check_Null(hx509_validate_ctx ctx, enum critical_flag cf, const Extension *e) +{ + switch(cf) { + case D_C: + break; + case S_C: + if (!e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tCritical not set on SHOULD\n"); + break; + case S_N_C: + if (e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tCritical set on SHOULD NOT\n"); + break; + case M_C: + if (!e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tCritical not set on MUST\n"); + break; + case M_N_C: + if (e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tCritical set on MUST NOT\n"); + break; + default: + abort(); + } + return 0; +} + +static int +check_subjectKeyIdentifier(hx509_validate_ctx ctx, + enum critical_flag cf, + const Extension *e) +{ + check_Null(ctx, cf, e); + return 0; +} + +static int +check_subjectAltName(hx509_validate_ctx ctx, + enum critical_flag cf, + const Extension *e) +{ + GeneralNames gn; + size_t size; + int ret; + + check_Null(ctx, cf, e); + + ret = decode_GeneralNames(e->extnValue.data, e->extnValue.length, + &gn, &size); + if (ret) { + printf("\tret = %d while decoding GeneralNames\n", ret); + return 0; + } + + free_GeneralNames(&gn); + + return 0; +} + +static int +check_basicConstraints(hx509_validate_ctx ctx, + enum critical_flag cf, + const Extension *e) +{ + BasicConstraints b; + size_t size; + int ret; + + check_Null(ctx, cf, e); + + ret = decode_BasicConstraints(e->extnValue.data, e->extnValue.length, + &b, &size); + if (ret) { + printf("\tret = %d while decoding BasicConstraints\n", ret); + return 0; + } + if (size != e->extnValue.length) + printf("\tlength of der data isn't same as extension\n"); + + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\tis %sa CA\n", b.cA && *b.cA ? "" : "NOT "); + if (b.pathLenConstraint) + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\tpathLenConstraint: %d\n", *b.pathLenConstraint); + + return 0; +} + +struct { + const char *name; + const heim_oid *(*oid)(void); + int (*func)(hx509_validate_ctx ctx, + enum critical_flag cf, + const Extension *); + enum critical_flag cf; +} check_extension[] = { +#define ext(name, checkname) #name, &oid_id_x509_ce_##name, check_##checkname + { ext(subjectDirectoryAttributes, Null), M_N_C }, + { ext(subjectKeyIdentifier, subjectKeyIdentifier), M_N_C }, + { ext(keyUsage, Null), S_C }, + { ext(subjectAltName, subjectAltName), M_N_C }, + { ext(issuerAltName, Null), S_N_C }, + { ext(basicConstraints, basicConstraints), M_C }, + { ext(cRLNumber, Null), M_N_C }, + { ext(cRLReasons, Null), M_N_C }, + { ext(holdInstructionCode, Null), M_N_C }, + { ext(invalidityDate, Null), M_N_C }, + { ext(deltaCRLIndicator, Null), M_C }, + { ext(issuingDistributionPoint, Null), M_C }, + { ext(certificateIssuer, Null), M_C }, + { ext(nameConstraints, Null), M_C }, + { ext(cRLDistributionPoints, Null), S_N_C }, + { ext(certificatePolicies, Null) }, + { ext(policyMappings, Null), M_N_C }, + { ext(authorityKeyIdentifier, Null), M_N_C }, + { ext(policyConstraints, Null), D_C }, + { ext(extKeyUsage, Null), D_C }, + { ext(freshestCRL, Null), M_N_C }, + { ext(inhibitAnyPolicy, Null), M_C }, + { NULL } +}; + +int +hx509_validate_ctx_init(hx509_validate_ctx *ctx) +{ + *ctx = malloc(sizeof(**ctx)); + if (*ctx == NULL) + return ENOMEM; + memset(*ctx, 0, sizeof(**ctx)); + return 0; +} + +void +hx509_validate_ctx_set_print(hx509_validate_ctx ctx, + hx509_vprint_func func, + void *c) +{ + ctx->vprint_func = func; + ctx->ctx = c; +} + +void +hx509_validate_ctx_add_flags(hx509_validate_ctx ctx, int flags) +{ + ctx->flags |= flags; +} + +void +hx509_validate_ctx_free(hx509_validate_ctx ctx) +{ + free(ctx); +} + +int +hx509_validate_cert(hx509_validate_ctx ctx, hx509_cert cert) +{ + Certificate *c = _hx509_get_cert(cert); + TBSCertificate *t = &c->tbsCertificate; + hx509_name name; + char *str; + + if (_hx509_cert_get_version(c) != 3) + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "Not version 3 certificate\n"); + + if (t->version && *t->version < 2 && t->extensions) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Not version 3 certificate with extensions\n"); + + _hx509_name_from_Name(&t->subject, &name); + hx509_name_to_string(name, &str); + hx509_name_free(&name); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "subject name: %s\n", str); + free(str); + + _hx509_name_from_Name(&t->issuer, &name); + hx509_name_to_string(name, &str); + hx509_name_free(&name); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "issuer name: %s\n", str); + free(str); + + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "Validity:\n"); + + Time2string(&t->validity.notBefore, &str); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotBefore %s\n", str); + free(str); + Time2string(&t->validity.notAfter, &str); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotAfter %s\n", str); + free(str); + + if (t->extensions) { + int i, j; + + if (t->extensions->len == 0) { + validate_print(ctx, + HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE, + "The empty extensions list is not " + "allowed by PKIX\n"); + } + + for (i = 0; i < t->extensions->len; i++) { + + for (j = 0; check_extension[j].name; j++) + if (heim_oid_cmp((*check_extension[j].oid)(), + &t->extensions->val[i].extnID) == 0) + break; + if (check_extension[j].name == NULL) { + int flags = HX509_VALIDATE_F_VERBOSE; + if (t->extensions->val[i].critical) + flags |= HX509_VALIDATE_F_VALIDATE; + validate_print(ctx, flags, "don't know what "); + if (t->extensions->val[i].critical) + validate_print(ctx, flags, "and is CRITICAL "); + if (ctx->flags & flags) + hx509_oid_print(&t->extensions->val[i].extnID, + validate_vprint, ctx); + validate_print(ctx, flags, " is\n"); + continue; + } + validate_print(ctx, + HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE, + "checking extention: %s\n", + check_extension[j].name); + (*check_extension[j].func)(ctx, + check_extension[j].cf, + &t->extensions->val[i]); + } + } else + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "no extentions\n"); + + return 0; +} diff --git a/lib/hx509/ref/pkcs11.h b/lib/hx509/ref/pkcs11.h new file mode 100644 index 000000000..dcc32a25a --- /dev/null +++ b/lib/hx509/ref/pkcs11.h @@ -0,0 +1,299 @@ +/* pkcs11.h include file for PKCS #11. */ +/* $Revision$ */ + +/* License to copy and use this software is granted provided that it is + * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface + * (Cryptoki)" in all material mentioning or referencing this software. + + * License is also granted to make and use derivative works provided that + * such works are identified as "derived from the RSA Security Inc. PKCS #11 + * Cryptographic Token Interface (Cryptoki)" in all material mentioning or + * referencing the derived work. + + * RSA Security Inc. makes no representations concerning either the + * merchantability of this software or the suitability of this software for + * any particular purpose. It is provided "as is" without express or implied + * warranty of any kind. + */ + +#ifndef _PKCS11_H_ +#define _PKCS11_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Before including this file (pkcs11.h) (or pkcs11t.h by + * itself), 6 platform-specific macros must be defined. These + * macros are described below, and typical definitions for them + * are also given. Be advised that these definitions can depend + * on both the platform and the compiler used (and possibly also + * on whether a Cryptoki library is linked statically or + * dynamically). + * + * In addition to defining these 6 macros, the packing convention + * for Cryptoki structures should be set. The Cryptoki + * convention on packing is that structures should be 1-byte + * aligned. + * + * If you're using Microsoft Developer Studio 5.0 to produce + * Win32 stuff, this might be done by using the following + * preprocessor directive before including pkcs11.h or pkcs11t.h: + * + * #pragma pack(push, cryptoki, 1) + * + * and using the following preprocessor directive after including + * pkcs11.h or pkcs11t.h: + * + * #pragma pack(pop, cryptoki) + * + * If you're using an earlier version of Microsoft Developer + * Studio to produce Win16 stuff, this might be done by using + * the following preprocessor directive before including + * pkcs11.h or pkcs11t.h: + * + * #pragma pack(1) + * + * In a UNIX environment, you're on your own for this. You might + * not need to do (or be able to do!) anything. + * + * + * Now for the macros: + * + * + * 1. CK_PTR: The indirection string for making a pointer to an + * object. It can be used like this: + * + * typedef CK_BYTE CK_PTR CK_BYTE_PTR; + * + * If you're using Microsoft Developer Studio 5.0 to produce + * Win32 stuff, it might be defined by: + * + * #define CK_PTR * + * + * If you're using an earlier version of Microsoft Developer + * Studio to produce Win16 stuff, it might be defined by: + * + * #define CK_PTR far * + * + * In a typical UNIX environment, it might be defined by: + * + * #define CK_PTR * + * + * + * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes + * an exportable Cryptoki library function definition out of a + * return type and a function name. It should be used in the + * following fashion to define the exposed Cryptoki functions in + * a Cryptoki library: + * + * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)( + * CK_VOID_PTR pReserved + * ) + * { + * ... + * } + * + * If you're using Microsoft Developer Studio 5.0 to define a + * function in a Win32 Cryptoki .dll, it might be defined by: + * + * #define CK_DEFINE_FUNCTION(returnType, name) \ + * returnType __declspec(dllexport) name + * + * If you're using an earlier version of Microsoft Developer + * Studio to define a function in a Win16 Cryptoki .dll, it + * might be defined by: + * + * #define CK_DEFINE_FUNCTION(returnType, name) \ + * returnType __export _far _pascal name + * + * In a UNIX environment, it might be defined by: + * + * #define CK_DEFINE_FUNCTION(returnType, name) \ + * returnType name + * + * + * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes + * an importable Cryptoki library function declaration out of a + * return type and a function name. It should be used in the + * following fashion: + * + * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)( + * CK_VOID_PTR pReserved + * ); + * + * If you're using Microsoft Developer Studio 5.0 to declare a + * function in a Win32 Cryptoki .dll, it might be defined by: + * + * #define CK_DECLARE_FUNCTION(returnType, name) \ + * returnType __declspec(dllimport) name + * + * If you're using an earlier version of Microsoft Developer + * Studio to declare a function in a Win16 Cryptoki .dll, it + * might be defined by: + * + * #define CK_DECLARE_FUNCTION(returnType, name) \ + * returnType __export _far _pascal name + * + * In a UNIX environment, it might be defined by: + * + * #define CK_DECLARE_FUNCTION(returnType, name) \ + * returnType name + * + * + * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro + * which makes a Cryptoki API function pointer declaration or + * function pointer type declaration out of a return type and a + * function name. It should be used in the following fashion: + * + * // Define funcPtr to be a pointer to a Cryptoki API function + * // taking arguments args and returning CK_RV. + * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args); + * + * or + * + * // Define funcPtrType to be the type of a pointer to a + * // Cryptoki API function taking arguments args and returning + * // CK_RV, and then define funcPtr to be a variable of type + * // funcPtrType. + * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args); + * funcPtrType funcPtr; + * + * If you're using Microsoft Developer Studio 5.0 to access + * functions in a Win32 Cryptoki .dll, in might be defined by: + * + * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ + * returnType __declspec(dllimport) (* name) + * + * If you're using an earlier version of Microsoft Developer + * Studio to access functions in a Win16 Cryptoki .dll, it might + * be defined by: + * + * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ + * returnType __export _far _pascal (* name) + * + * In a UNIX environment, it might be defined by: + * + * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ + * returnType (* name) + * + * + * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes + * a function pointer type for an application callback out of + * a return type for the callback and a name for the callback. + * It should be used in the following fashion: + * + * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args); + * + * to declare a function pointer, myCallback, to a callback + * which takes arguments args and returns a CK_RV. It can also + * be used like this: + * + * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args); + * myCallbackType myCallback; + * + * If you're using Microsoft Developer Studio 5.0 to do Win32 + * Cryptoki development, it might be defined by: + * + * #define CK_CALLBACK_FUNCTION(returnType, name) \ + * returnType (* name) + * + * If you're using an earlier version of Microsoft Developer + * Studio to do Win16 development, it might be defined by: + * + * #define CK_CALLBACK_FUNCTION(returnType, name) \ + * returnType _far _pascal (* name) + * + * In a UNIX environment, it might be defined by: + * + * #define CK_CALLBACK_FUNCTION(returnType, name) \ + * returnType (* name) + * + * + * 6. NULL_PTR: This macro is the value of a NULL pointer. + * + * In any ANSI/ISO C environment (and in many others as well), + * this should best be defined by + * + * #ifndef NULL_PTR + * #define NULL_PTR 0 + * #endif + */ + + +/* All the various Cryptoki types and #define'd values are in the + * file pkcs11t.h. */ +#include "pkcs11t.h" + +#define __PASTE(x,y) x##y + + +/* ============================================================== + * Define the "extern" form of all the entry points. + * ============================================================== + */ + +#define CK_NEED_ARG_LIST 1 +#define CK_PKCS11_FUNCTION_INFO(name) \ + extern CK_DECLARE_FUNCTION(CK_RV, name) + +/* pkcs11f.h has all the information about the Cryptoki + * function prototypes. */ +#include "pkcs11f.h" + +#undef CK_NEED_ARG_LIST +#undef CK_PKCS11_FUNCTION_INFO + + +/* ============================================================== + * Define the typedef form of all the entry points. That is, for + * each Cryptoki function C_XXX, define a type CK_C_XXX which is + * a pointer to that kind of function. + * ============================================================== + */ + +#define CK_NEED_ARG_LIST 1 +#define CK_PKCS11_FUNCTION_INFO(name) \ + typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name)) + +/* pkcs11f.h has all the information about the Cryptoki + * function prototypes. */ +#include "pkcs11f.h" + +#undef CK_NEED_ARG_LIST +#undef CK_PKCS11_FUNCTION_INFO + + +/* ============================================================== + * Define structed vector of entry points. A CK_FUNCTION_LIST + * contains a CK_VERSION indicating a library's Cryptoki version + * and then a whole slew of function pointers to the routines in + * the library. This type was declared, but not defined, in + * pkcs11t.h. + * ============================================================== + */ + +#define CK_PKCS11_FUNCTION_INFO(name) \ + __PASTE(CK_,name) name; + +struct CK_FUNCTION_LIST { + + CK_VERSION version; /* Cryptoki version */ + +/* Pile all the function pointers into the CK_FUNCTION_LIST. */ +/* pkcs11f.h has all the information about the Cryptoki + * function prototypes. */ +#include "pkcs11f.h" + +}; + +#undef CK_PKCS11_FUNCTION_INFO + + +#undef __PASTE + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/hx509/ref/pkcs11f.h b/lib/hx509/ref/pkcs11f.h new file mode 100644 index 000000000..bbd3e8505 --- /dev/null +++ b/lib/hx509/ref/pkcs11f.h @@ -0,0 +1,912 @@ +/* pkcs11f.h include file for PKCS #11. */ +/* $Revision$ */ + +/* License to copy and use this software is granted provided that it is + * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface + * (Cryptoki)" in all material mentioning or referencing this software. + + * License is also granted to make and use derivative works provided that + * such works are identified as "derived from the RSA Security Inc. PKCS #11 + * Cryptographic Token Interface (Cryptoki)" in all material mentioning or + * referencing the derived work. + + * RSA Security Inc. makes no representations concerning either the + * merchantability of this software or the suitability of this software for + * any particular purpose. It is provided "as is" without express or implied + * warranty of any kind. + */ + +/* This header file contains pretty much everything about all the */ +/* Cryptoki function prototypes. Because this information is */ +/* used for more than just declaring function prototypes, the */ +/* order of the functions appearing herein is important, and */ +/* should not be altered. */ + +/* General-purpose */ + +/* C_Initialize initializes the Cryptoki library. */ +CK_PKCS11_FUNCTION_INFO(C_Initialize) +#ifdef CK_NEED_ARG_LIST +( + CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets + * cast to CK_C_INITIALIZE_ARGS_PTR + * and dereferenced */ +); +#endif + + +/* C_Finalize indicates that an application is done with the + * Cryptoki library. */ +CK_PKCS11_FUNCTION_INFO(C_Finalize) +#ifdef CK_NEED_ARG_LIST +( + CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */ +); +#endif + + +/* C_GetInfo returns general information about Cryptoki. */ +CK_PKCS11_FUNCTION_INFO(C_GetInfo) +#ifdef CK_NEED_ARG_LIST +( + CK_INFO_PTR pInfo /* location that receives information */ +); +#endif + + +/* C_GetFunctionList returns the function list. */ +CK_PKCS11_FUNCTION_INFO(C_GetFunctionList) +#ifdef CK_NEED_ARG_LIST +( + CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to + * function list */ +); +#endif + + + +/* Slot and token management */ + +/* C_GetSlotList obtains a list of slots in the system. */ +CK_PKCS11_FUNCTION_INFO(C_GetSlotList) +#ifdef CK_NEED_ARG_LIST +( + CK_BBOOL tokenPresent, /* only slots with tokens? */ + CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */ + CK_ULONG_PTR pulCount /* receives number of slots */ +); +#endif + + +/* C_GetSlotInfo obtains information about a particular slot in + * the system. */ +CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo) +#ifdef CK_NEED_ARG_LIST +( + CK_SLOT_ID slotID, /* the ID of the slot */ + CK_SLOT_INFO_PTR pInfo /* receives the slot information */ +); +#endif + + +/* C_GetTokenInfo obtains information about a particular token + * in the system. */ +CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo) +#ifdef CK_NEED_ARG_LIST +( + CK_SLOT_ID slotID, /* ID of the token's slot */ + CK_TOKEN_INFO_PTR pInfo /* receives the token information */ +); +#endif + + +/* C_GetMechanismList obtains a list of mechanism types + * supported by a token. */ +CK_PKCS11_FUNCTION_INFO(C_GetMechanismList) +#ifdef CK_NEED_ARG_LIST +( + CK_SLOT_ID slotID, /* ID of token's slot */ + CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */ + CK_ULONG_PTR pulCount /* gets # of mechs. */ +); +#endif + + +/* C_GetMechanismInfo obtains information about a particular + * mechanism possibly supported by a token. */ +CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo) +#ifdef CK_NEED_ARG_LIST +( + CK_SLOT_ID slotID, /* ID of the token's slot */ + CK_MECHANISM_TYPE type, /* type of mechanism */ + CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */ +); +#endif + + +/* C_InitToken initializes a token. */ +CK_PKCS11_FUNCTION_INFO(C_InitToken) +#ifdef CK_NEED_ARG_LIST +/* pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10 */ +( + CK_SLOT_ID slotID, /* ID of the token's slot */ + CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */ + CK_ULONG ulPinLen, /* length in bytes of the PIN */ + CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */ +); +#endif + + +/* C_InitPIN initializes the normal user's PIN. */ +CK_PKCS11_FUNCTION_INFO(C_InitPIN) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */ + CK_ULONG ulPinLen /* length in bytes of the PIN */ +); +#endif + + +/* C_SetPIN modifies the PIN of the user who is logged in. */ +CK_PKCS11_FUNCTION_INFO(C_SetPIN) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_UTF8CHAR_PTR pOldPin, /* the old PIN */ + CK_ULONG ulOldLen, /* length of the old PIN */ + CK_UTF8CHAR_PTR pNewPin, /* the new PIN */ + CK_ULONG ulNewLen /* length of the new PIN */ +); +#endif + + + +/* Session management */ + +/* C_OpenSession opens a session between an application and a + * token. */ +CK_PKCS11_FUNCTION_INFO(C_OpenSession) +#ifdef CK_NEED_ARG_LIST +( + CK_SLOT_ID slotID, /* the slot's ID */ + CK_FLAGS flags, /* from CK_SESSION_INFO */ + CK_VOID_PTR pApplication, /* passed to callback */ + CK_NOTIFY Notify, /* callback function */ + CK_SESSION_HANDLE_PTR phSession /* gets session handle */ +); +#endif + + +/* C_CloseSession closes a session between an application and a + * token. */ +CK_PKCS11_FUNCTION_INFO(C_CloseSession) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession /* the session's handle */ +); +#endif + + +/* C_CloseAllSessions closes all sessions with a token. */ +CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions) +#ifdef CK_NEED_ARG_LIST +( + CK_SLOT_ID slotID /* the token's slot */ +); +#endif + + +/* C_GetSessionInfo obtains information about the session. */ +CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_SESSION_INFO_PTR pInfo /* receives session info */ +); +#endif + + +/* C_GetOperationState obtains the state of the cryptographic operation + * in a session. */ +CK_PKCS11_FUNCTION_INFO(C_GetOperationState) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pOperationState, /* gets state */ + CK_ULONG_PTR pulOperationStateLen /* gets state length */ +); +#endif + + +/* C_SetOperationState restores the state of the cryptographic + * operation in a session. */ +CK_PKCS11_FUNCTION_INFO(C_SetOperationState) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pOperationState, /* holds state */ + CK_ULONG ulOperationStateLen, /* holds state length */ + CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */ + CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */ +); +#endif + + +/* C_Login logs a user into a token. */ +CK_PKCS11_FUNCTION_INFO(C_Login) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_USER_TYPE userType, /* the user type */ + CK_UTF8CHAR_PTR pPin, /* the user's PIN */ + CK_ULONG ulPinLen /* the length of the PIN */ +); +#endif + + +/* C_Logout logs a user out from a token. */ +CK_PKCS11_FUNCTION_INFO(C_Logout) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession /* the session's handle */ +); +#endif + + + +/* Object management */ + +/* C_CreateObject creates a new object. */ +CK_PKCS11_FUNCTION_INFO(C_CreateObject) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_ATTRIBUTE_PTR pTemplate, /* the object's template */ + CK_ULONG ulCount, /* attributes in template */ + CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */ +); +#endif + + +/* C_CopyObject copies an object, creating a new object for the + * copy. */ +CK_PKCS11_FUNCTION_INFO(C_CopyObject) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_OBJECT_HANDLE hObject, /* the object's handle */ + CK_ATTRIBUTE_PTR pTemplate, /* template for new object */ + CK_ULONG ulCount, /* attributes in template */ + CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */ +); +#endif + + +/* C_DestroyObject destroys an object. */ +CK_PKCS11_FUNCTION_INFO(C_DestroyObject) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_OBJECT_HANDLE hObject /* the object's handle */ +); +#endif + + +/* C_GetObjectSize gets the size of an object in bytes. */ +CK_PKCS11_FUNCTION_INFO(C_GetObjectSize) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_OBJECT_HANDLE hObject, /* the object's handle */ + CK_ULONG_PTR pulSize /* receives size of object */ +); +#endif + + +/* C_GetAttributeValue obtains the value of one or more object + * attributes. */ +CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_OBJECT_HANDLE hObject, /* the object's handle */ + CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */ + CK_ULONG ulCount /* attributes in template */ +); +#endif + + +/* C_SetAttributeValue modifies the value of one or more object + * attributes */ +CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_OBJECT_HANDLE hObject, /* the object's handle */ + CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */ + CK_ULONG ulCount /* attributes in template */ +); +#endif + + +/* C_FindObjectsInit initializes a search for token and session + * objects that match a template. */ +CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */ + CK_ULONG ulCount /* attrs in search template */ +); +#endif + + +/* C_FindObjects continues a search for token and session + * objects that match a template, obtaining additional object + * handles. */ +CK_PKCS11_FUNCTION_INFO(C_FindObjects) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */ + CK_ULONG ulMaxObjectCount, /* max handles to get */ + CK_ULONG_PTR pulObjectCount /* actual # returned */ +); +#endif + + +/* C_FindObjectsFinal finishes a search for token and session + * objects. */ +CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession /* the session's handle */ +); +#endif + + + +/* Encryption and decryption */ + +/* C_EncryptInit initializes an encryption operation. */ +CK_PKCS11_FUNCTION_INFO(C_EncryptInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */ + CK_OBJECT_HANDLE hKey /* handle of encryption key */ +); +#endif + + +/* C_Encrypt encrypts single-part data. */ +CK_PKCS11_FUNCTION_INFO(C_Encrypt) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pData, /* the plaintext data */ + CK_ULONG ulDataLen, /* bytes of plaintext */ + CK_BYTE_PTR pEncryptedData, /* gets ciphertext */ + CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */ +); +#endif + + +/* C_EncryptUpdate continues a multiple-part encryption + * operation. */ +CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pPart, /* the plaintext data */ + CK_ULONG ulPartLen, /* plaintext data len */ + CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ + CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */ +); +#endif + + +/* C_EncryptFinal finishes a multiple-part encryption + * operation. */ +CK_PKCS11_FUNCTION_INFO(C_EncryptFinal) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session handle */ + CK_BYTE_PTR pLastEncryptedPart, /* last c-text */ + CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */ +); +#endif + + +/* C_DecryptInit initializes a decryption operation. */ +CK_PKCS11_FUNCTION_INFO(C_DecryptInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */ + CK_OBJECT_HANDLE hKey /* handle of decryption key */ +); +#endif + + +/* C_Decrypt decrypts encrypted data in a single part. */ +CK_PKCS11_FUNCTION_INFO(C_Decrypt) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pEncryptedData, /* ciphertext */ + CK_ULONG ulEncryptedDataLen, /* ciphertext length */ + CK_BYTE_PTR pData, /* gets plaintext */ + CK_ULONG_PTR pulDataLen /* gets p-text size */ +); +#endif + + +/* C_DecryptUpdate continues a multiple-part decryption + * operation. */ +CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pEncryptedPart, /* encrypted data */ + CK_ULONG ulEncryptedPartLen, /* input length */ + CK_BYTE_PTR pPart, /* gets plaintext */ + CK_ULONG_PTR pulPartLen /* p-text size */ +); +#endif + + +/* C_DecryptFinal finishes a multiple-part decryption + * operation. */ +CK_PKCS11_FUNCTION_INFO(C_DecryptFinal) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pLastPart, /* gets plaintext */ + CK_ULONG_PTR pulLastPartLen /* p-text size */ +); +#endif + + + +/* Message digesting */ + +/* C_DigestInit initializes a message-digesting operation. */ +CK_PKCS11_FUNCTION_INFO(C_DigestInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism /* the digesting mechanism */ +); +#endif + + +/* C_Digest digests data in a single part. */ +CK_PKCS11_FUNCTION_INFO(C_Digest) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pData, /* data to be digested */ + CK_ULONG ulDataLen, /* bytes of data to digest */ + CK_BYTE_PTR pDigest, /* gets the message digest */ + CK_ULONG_PTR pulDigestLen /* gets digest length */ +); +#endif + + +/* C_DigestUpdate continues a multiple-part message-digesting + * operation. */ +CK_PKCS11_FUNCTION_INFO(C_DigestUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pPart, /* data to be digested */ + CK_ULONG ulPartLen /* bytes of data to be digested */ +); +#endif + + +/* C_DigestKey continues a multi-part message-digesting + * operation, by digesting the value of a secret key as part of + * the data already digested. */ +CK_PKCS11_FUNCTION_INFO(C_DigestKey) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_OBJECT_HANDLE hKey /* secret key to digest */ +); +#endif + + +/* C_DigestFinal finishes a multiple-part message-digesting + * operation. */ +CK_PKCS11_FUNCTION_INFO(C_DigestFinal) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pDigest, /* gets the message digest */ + CK_ULONG_PTR pulDigestLen /* gets byte count of digest */ +); +#endif + + + +/* Signing and MACing */ + +/* C_SignInit initializes a signature (private key encryption) + * operation, where the signature is (will be) an appendix to + * the data, and plaintext cannot be recovered from the + *signature. */ +CK_PKCS11_FUNCTION_INFO(C_SignInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* the signature mechanism */ + CK_OBJECT_HANDLE hKey /* handle of signature key */ +); +#endif + + +/* C_Sign signs (encrypts with private key) data in a single + * part, where the signature is (will be) an appendix to the + * data, and plaintext cannot be recovered from the signature. */ +CK_PKCS11_FUNCTION_INFO(C_Sign) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pData, /* the data to sign */ + CK_ULONG ulDataLen, /* count of bytes to sign */ + CK_BYTE_PTR pSignature, /* gets the signature */ + CK_ULONG_PTR pulSignatureLen /* gets signature length */ +); +#endif + + +/* C_SignUpdate continues a multiple-part signature operation, + * where the signature is (will be) an appendix to the data, + * and plaintext cannot be recovered from the signature. */ +CK_PKCS11_FUNCTION_INFO(C_SignUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pPart, /* the data to sign */ + CK_ULONG ulPartLen /* count of bytes to sign */ +); +#endif + + +/* C_SignFinal finishes a multiple-part signature operation, + * returning the signature. */ +CK_PKCS11_FUNCTION_INFO(C_SignFinal) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pSignature, /* gets the signature */ + CK_ULONG_PTR pulSignatureLen /* gets signature length */ +); +#endif + + +/* C_SignRecoverInit initializes a signature operation, where + * the data can be recovered from the signature. */ +CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* the signature mechanism */ + CK_OBJECT_HANDLE hKey /* handle of the signature key */ +); +#endif + + +/* C_SignRecover signs data in a single operation, where the + * data can be recovered from the signature. */ +CK_PKCS11_FUNCTION_INFO(C_SignRecover) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pData, /* the data to sign */ + CK_ULONG ulDataLen, /* count of bytes to sign */ + CK_BYTE_PTR pSignature, /* gets the signature */ + CK_ULONG_PTR pulSignatureLen /* gets signature length */ +); +#endif + + + +/* Verifying signatures and MACs */ + +/* C_VerifyInit initializes a verification operation, where the + * signature is an appendix to the data, and plaintext cannot + * cannot be recovered from the signature (e.g. DSA). */ +CK_PKCS11_FUNCTION_INFO(C_VerifyInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* the verification mechanism */ + CK_OBJECT_HANDLE hKey /* verification key */ +); +#endif + + +/* C_Verify verifies a signature in a single-part operation, + * where the signature is an appendix to the data, and plaintext + * cannot be recovered from the signature. */ +CK_PKCS11_FUNCTION_INFO(C_Verify) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pData, /* signed data */ + CK_ULONG ulDataLen, /* length of signed data */ + CK_BYTE_PTR pSignature, /* signature */ + CK_ULONG ulSignatureLen /* signature length*/ +); +#endif + + +/* C_VerifyUpdate continues a multiple-part verification + * operation, where the signature is an appendix to the data, + * and plaintext cannot be recovered from the signature. */ +CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pPart, /* signed data */ + CK_ULONG ulPartLen /* length of signed data */ +); +#endif + + +/* C_VerifyFinal finishes a multiple-part verification + * operation, checking the signature. */ +CK_PKCS11_FUNCTION_INFO(C_VerifyFinal) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pSignature, /* signature to verify */ + CK_ULONG ulSignatureLen /* signature length */ +); +#endif + + +/* C_VerifyRecoverInit initializes a signature verification + * operation, where the data is recovered from the signature. */ +CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* the verification mechanism */ + CK_OBJECT_HANDLE hKey /* verification key */ +); +#endif + + +/* C_VerifyRecover verifies a signature in a single-part + * operation, where the data is recovered from the signature. */ +CK_PKCS11_FUNCTION_INFO(C_VerifyRecover) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pSignature, /* signature to verify */ + CK_ULONG ulSignatureLen, /* signature length */ + CK_BYTE_PTR pData, /* gets signed data */ + CK_ULONG_PTR pulDataLen /* gets signed data len */ +); +#endif + + + +/* Dual-function cryptographic operations */ + +/* C_DigestEncryptUpdate continues a multiple-part digesting + * and encryption operation. */ +CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pPart, /* the plaintext data */ + CK_ULONG ulPartLen, /* plaintext length */ + CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ + CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */ +); +#endif + + +/* C_DecryptDigestUpdate continues a multiple-part decryption and + * digesting operation. */ +CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pEncryptedPart, /* ciphertext */ + CK_ULONG ulEncryptedPartLen, /* ciphertext length */ + CK_BYTE_PTR pPart, /* gets plaintext */ + CK_ULONG_PTR pulPartLen /* gets plaintext len */ +); +#endif + + +/* C_SignEncryptUpdate continues a multiple-part signing and + * encryption operation. */ +CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pPart, /* the plaintext data */ + CK_ULONG ulPartLen, /* plaintext length */ + CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ + CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */ +); +#endif + + +/* C_DecryptVerifyUpdate continues a multiple-part decryption and + * verify operation. */ +CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pEncryptedPart, /* ciphertext */ + CK_ULONG ulEncryptedPartLen, /* ciphertext length */ + CK_BYTE_PTR pPart, /* gets plaintext */ + CK_ULONG_PTR pulPartLen /* gets p-text length */ +); +#endif + + + +/* Key management */ + +/* C_GenerateKey generates a secret key, creating a new key + * object. */ +CK_PKCS11_FUNCTION_INFO(C_GenerateKey) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* key generation mech. */ + CK_ATTRIBUTE_PTR pTemplate, /* template for new key */ + CK_ULONG ulCount, /* # of attrs in template */ + CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */ +); +#endif + + +/* C_GenerateKeyPair generates a public-key/private-key pair, + * creating new key objects. */ +CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session + * handle */ + CK_MECHANISM_PTR pMechanism, /* key-gen + * mech. */ + CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template + * for pub. + * key */ + CK_ULONG ulPublicKeyAttributeCount, /* # pub. + * attrs. */ + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template + * for priv. + * key */ + CK_ULONG ulPrivateKeyAttributeCount, /* # priv. + * attrs. */ + CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub. + * key + * handle */ + CK_OBJECT_HANDLE_PTR phPrivateKey /* gets + * priv. key + * handle */ +); +#endif + + +/* C_WrapKey wraps (i.e., encrypts) a key. */ +CK_PKCS11_FUNCTION_INFO(C_WrapKey) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */ + CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */ + CK_OBJECT_HANDLE hKey, /* key to be wrapped */ + CK_BYTE_PTR pWrappedKey, /* gets wrapped key */ + CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */ +); +#endif + + +/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new + * key object. */ +CK_PKCS11_FUNCTION_INFO(C_UnwrapKey) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */ + CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */ + CK_BYTE_PTR pWrappedKey, /* the wrapped key */ + CK_ULONG ulWrappedKeyLen, /* wrapped key len */ + CK_ATTRIBUTE_PTR pTemplate, /* new key template */ + CK_ULONG ulAttributeCount, /* template length */ + CK_OBJECT_HANDLE_PTR phKey /* gets new handle */ +); +#endif + + +/* C_DeriveKey derives a key from a base key, creating a new key + * object. */ +CK_PKCS11_FUNCTION_INFO(C_DeriveKey) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */ + CK_OBJECT_HANDLE hBaseKey, /* base key */ + CK_ATTRIBUTE_PTR pTemplate, /* new key template */ + CK_ULONG ulAttributeCount, /* template length */ + CK_OBJECT_HANDLE_PTR phKey /* gets new handle */ +); +#endif + + + +/* Random number generation */ + +/* C_SeedRandom mixes additional seed material into the token's + * random number generator. */ +CK_PKCS11_FUNCTION_INFO(C_SeedRandom) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pSeed, /* the seed material */ + CK_ULONG ulSeedLen /* length of seed material */ +); +#endif + + +/* C_GenerateRandom generates random data. */ +CK_PKCS11_FUNCTION_INFO(C_GenerateRandom) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR RandomData, /* receives the random data */ + CK_ULONG ulRandomLen /* # of bytes to generate */ +); +#endif + + + +/* Parallel function management */ + +/* C_GetFunctionStatus is a legacy function; it obtains an + * updated status of a function running in parallel with an + * application. */ +CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession /* the session's handle */ +); +#endif + + +/* C_CancelFunction is a legacy function; it cancels a function + * running in parallel. */ +CK_PKCS11_FUNCTION_INFO(C_CancelFunction) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession /* the session's handle */ +); +#endif + + + +/* Functions added in for Cryptoki Version 2.01 or later */ + +/* C_WaitForSlotEvent waits for a slot event (token insertion, + * removal, etc.) to occur. */ +CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent) +#ifdef CK_NEED_ARG_LIST +( + CK_FLAGS flags, /* blocking/nonblocking flag */ + CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */ + CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */ +); +#endif diff --git a/lib/hx509/ref/pkcs11t.h b/lib/hx509/ref/pkcs11t.h new file mode 100644 index 000000000..f1e6592f5 --- /dev/null +++ b/lib/hx509/ref/pkcs11t.h @@ -0,0 +1,1440 @@ +/* pkcs11t.h include file for PKCS #11. */ +/* $Revision$ */ + +/* License to copy and use this software is granted provided that it is + * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface + * (Cryptoki)" in all material mentioning or referencing this software. + + * License is also granted to make and use derivative works provided that + * such works are identified as "derived from the RSA Security Inc. PKCS #11 + * Cryptographic Token Interface (Cryptoki)" in all material mentioning or + * referencing the derived work. + + * RSA Security Inc. makes no representations concerning either the + * merchantability of this software or the suitability of this software for + * any particular purpose. It is provided "as is" without express or implied + * warranty of any kind. + */ + +/* See top of pkcs11.h for information about the macros that + * must be defined and the structure-packing conventions that + * must be set before including this file. */ + +#ifndef _PKCS11T_H_ +#define _PKCS11T_H_ 1 + +#ifndef CK_DISABLE_TRUE_FALSE +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE !(FALSE) +#endif +#endif + +#define CK_TRUE 1 +#define CK_FALSE 0 + +/* an unsigned 8-bit value */ +typedef unsigned char CK_BYTE; + +/* an unsigned 8-bit character */ +typedef CK_BYTE CK_CHAR; + +/* an 8-bit UTF-8 character */ +typedef CK_BYTE CK_UTF8CHAR; + +/* a BYTE-sized Boolean flag */ +typedef CK_BYTE CK_BBOOL; + +/* an unsigned value, at least 32 bits long */ +typedef unsigned long int CK_ULONG; + +/* a signed value, the same size as a CK_ULONG */ +/* CK_LONG is new for v2.0 */ +typedef long int CK_LONG; + +/* at least 32 bits; each bit is a Boolean flag */ +typedef CK_ULONG CK_FLAGS; + + +/* some special values for certain CK_ULONG variables */ +#define CK_UNAVAILABLE_INFORMATION (~0UL) +#define CK_EFFECTIVELY_INFINITE 0 + + +typedef CK_BYTE CK_PTR CK_BYTE_PTR; +typedef CK_CHAR CK_PTR CK_CHAR_PTR; +typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR; +typedef CK_ULONG CK_PTR CK_ULONG_PTR; +typedef void CK_PTR CK_VOID_PTR; + +/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */ +typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR; + + +/* The following value is always invalid if used as a session */ +/* handle or object handle */ +#define CK_INVALID_HANDLE 0 + + +typedef struct CK_VERSION { + CK_BYTE major; /* integer portion of version number */ + CK_BYTE minor; /* 1/100ths portion of version number */ +} CK_VERSION; + +typedef CK_VERSION CK_PTR CK_VERSION_PTR; + + +typedef struct CK_INFO { + /* manufacturerID and libraryDecription have been changed from + * CK_CHAR to CK_UTF8CHAR for v2.10 */ + CK_VERSION cryptokiVersion; /* Cryptoki interface ver */ + CK_UTF8CHAR manufacturerID[32]; /* blank padded */ + CK_FLAGS flags; /* must be zero */ + + /* libraryDescription and libraryVersion are new for v2.0 */ + CK_UTF8CHAR libraryDescription[32]; /* blank padded */ + CK_VERSION libraryVersion; /* version of library */ +} CK_INFO; + +typedef CK_INFO CK_PTR CK_INFO_PTR; + + +/* CK_NOTIFICATION enumerates the types of notifications that + * Cryptoki provides to an application */ +/* CK_NOTIFICATION has been changed from an enum to a CK_ULONG + * for v2.0 */ +typedef CK_ULONG CK_NOTIFICATION; +#define CKN_SURRENDER 0 + + +typedef CK_ULONG CK_SLOT_ID; + +typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR; + + +/* CK_SLOT_INFO provides information about a slot */ +typedef struct CK_SLOT_INFO { + /* slotDescription and manufacturerID have been changed from + * CK_CHAR to CK_UTF8CHAR for v2.10 */ + CK_UTF8CHAR slotDescription[64]; /* blank padded */ + CK_UTF8CHAR manufacturerID[32]; /* blank padded */ + CK_FLAGS flags; + + /* hardwareVersion and firmwareVersion are new for v2.0 */ + CK_VERSION hardwareVersion; /* version of hardware */ + CK_VERSION firmwareVersion; /* version of firmware */ +} CK_SLOT_INFO; + +/* flags: bit flags that provide capabilities of the slot + * Bit Flag Mask Meaning + */ +#define CKF_TOKEN_PRESENT 0x00000001 /* a token is there */ +#define CKF_REMOVABLE_DEVICE 0x00000002 /* removable devices*/ +#define CKF_HW_SLOT 0x00000004 /* hardware slot */ + +typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR; + + +/* CK_TOKEN_INFO provides information about a token */ +typedef struct CK_TOKEN_INFO { + /* label, manufacturerID, and model have been changed from + * CK_CHAR to CK_UTF8CHAR for v2.10 */ + CK_UTF8CHAR label[32]; /* blank padded */ + CK_UTF8CHAR manufacturerID[32]; /* blank padded */ + CK_UTF8CHAR model[16]; /* blank padded */ + CK_CHAR serialNumber[16]; /* blank padded */ + CK_FLAGS flags; /* see below */ + + /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount, + * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been + * changed from CK_USHORT to CK_ULONG for v2.0 */ + CK_ULONG ulMaxSessionCount; /* max open sessions */ + CK_ULONG ulSessionCount; /* sess. now open */ + CK_ULONG ulMaxRwSessionCount; /* max R/W sessions */ + CK_ULONG ulRwSessionCount; /* R/W sess. now open */ + CK_ULONG ulMaxPinLen; /* in bytes */ + CK_ULONG ulMinPinLen; /* in bytes */ + CK_ULONG ulTotalPublicMemory; /* in bytes */ + CK_ULONG ulFreePublicMemory; /* in bytes */ + CK_ULONG ulTotalPrivateMemory; /* in bytes */ + CK_ULONG ulFreePrivateMemory; /* in bytes */ + + /* hardwareVersion, firmwareVersion, and time are new for + * v2.0 */ + CK_VERSION hardwareVersion; /* version of hardware */ + CK_VERSION firmwareVersion; /* version of firmware */ + CK_CHAR utcTime[16]; /* time */ +} CK_TOKEN_INFO; + +/* The flags parameter is defined as follows: + * Bit Flag Mask Meaning + */ +#define CKF_RNG 0x00000001 /* has random # + * generator */ +#define CKF_WRITE_PROTECTED 0x00000002 /* token is + * write- + * protected */ +#define CKF_LOGIN_REQUIRED 0x00000004 /* user must + * login */ +#define CKF_USER_PIN_INITIALIZED 0x00000008 /* normal user's + * PIN is set */ + +/* CKF_RESTORE_KEY_NOT_NEEDED is new for v2.0. If it is set, + * that means that *every* time the state of cryptographic + * operations of a session is successfully saved, all keys + * needed to continue those operations are stored in the state */ +#define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020 + +/* CKF_CLOCK_ON_TOKEN is new for v2.0. If it is set, that means + * that the token has some sort of clock. The time on that + * clock is returned in the token info structure */ +#define CKF_CLOCK_ON_TOKEN 0x00000040 + +/* CKF_PROTECTED_AUTHENTICATION_PATH is new for v2.0. If it is + * set, that means that there is some way for the user to login + * without sending a PIN through the Cryptoki library itself */ +#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100 + +/* CKF_DUAL_CRYPTO_OPERATIONS is new for v2.0. If it is true, + * that means that a single session with the token can perform + * dual simultaneous cryptographic operations (digest and + * encrypt; decrypt and digest; sign and encrypt; and decrypt + * and sign) */ +#define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200 + +/* CKF_TOKEN_INITIALIZED if new for v2.10. If it is true, the + * token has been initialized using C_InitializeToken or an + * equivalent mechanism outside the scope of PKCS #11. + * Calling C_InitializeToken when this flag is set will cause + * the token to be reinitialized. */ +#define CKF_TOKEN_INITIALIZED 0x00000400 + +/* CKF_SECONDARY_AUTHENTICATION if new for v2.10. If it is + * true, the token supports secondary authentication for + * private key objects. */ +#define CKF_SECONDARY_AUTHENTICATION 0x00000800 + +/* CKF_USER_PIN_COUNT_LOW if new for v2.10. If it is true, an + * incorrect user login PIN has been entered at least once + * since the last successful authentication. */ +#define CKF_USER_PIN_COUNT_LOW 0x00010000 + +/* CKF_USER_PIN_FINAL_TRY if new for v2.10. If it is true, + * supplying an incorrect user PIN will it to become locked. */ +#define CKF_USER_PIN_FINAL_TRY 0x00020000 + +/* CKF_USER_PIN_LOCKED if new for v2.10. If it is true, the + * user PIN has been locked. User login to the token is not + * possible. */ +#define CKF_USER_PIN_LOCKED 0x00040000 + +/* CKF_USER_PIN_TO_BE_CHANGED if new for v2.10. If it is true, + * the user PIN value is the default value set by token + * initialization or manufacturing, or the PIN has been + * expired by the card. */ +#define CKF_USER_PIN_TO_BE_CHANGED 0x00080000 + +/* CKF_SO_PIN_COUNT_LOW if new for v2.10. If it is true, an + * incorrect SO login PIN has been entered at least once since + * the last successful authentication. */ +#define CKF_SO_PIN_COUNT_LOW 0x00100000 + +/* CKF_SO_PIN_FINAL_TRY if new for v2.10. If it is true, + * supplying an incorrect SO PIN will it to become locked. */ +#define CKF_SO_PIN_FINAL_TRY 0x00200000 + +/* CKF_SO_PIN_LOCKED if new for v2.10. If it is true, the SO + * PIN has been locked. SO login to the token is not possible. + */ +#define CKF_SO_PIN_LOCKED 0x00400000 + +/* CKF_SO_PIN_TO_BE_CHANGED if new for v2.10. If it is true, + * the SO PIN value is the default value set by token + * initialization or manufacturing, or the PIN has been + * expired by the card. */ +#define CKF_SO_PIN_TO_BE_CHANGED 0x00800000 + +typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR; + + +/* CK_SESSION_HANDLE is a Cryptoki-assigned value that + * identifies a session */ +typedef CK_ULONG CK_SESSION_HANDLE; + +typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR; + + +/* CK_USER_TYPE enumerates the types of Cryptoki users */ +/* CK_USER_TYPE has been changed from an enum to a CK_ULONG for + * v2.0 */ +typedef CK_ULONG CK_USER_TYPE; +/* Security Officer */ +#define CKU_SO 0 +/* Normal user */ +#define CKU_USER 1 + + +/* CK_STATE enumerates the session states */ +/* CK_STATE has been changed from an enum to a CK_ULONG for + * v2.0 */ +typedef CK_ULONG CK_STATE; +#define CKS_RO_PUBLIC_SESSION 0 +#define CKS_RO_USER_FUNCTIONS 1 +#define CKS_RW_PUBLIC_SESSION 2 +#define CKS_RW_USER_FUNCTIONS 3 +#define CKS_RW_SO_FUNCTIONS 4 + + +/* CK_SESSION_INFO provides information about a session */ +typedef struct CK_SESSION_INFO { + CK_SLOT_ID slotID; + CK_STATE state; + CK_FLAGS flags; /* see below */ + + /* ulDeviceError was changed from CK_USHORT to CK_ULONG for + * v2.0 */ + CK_ULONG ulDeviceError; /* device-dependent error code */ +} CK_SESSION_INFO; + +/* The flags are defined in the following table: + * Bit Flag Mask Meaning + */ +#define CKF_RW_SESSION 0x00000002 /* session is r/w */ +#define CKF_SERIAL_SESSION 0x00000004 /* no parallel */ + +typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR; + + +/* CK_OBJECT_HANDLE is a token-specific identifier for an + * object */ +typedef CK_ULONG CK_OBJECT_HANDLE; + +typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR; + + +/* CK_OBJECT_CLASS is a value that identifies the classes (or + * types) of objects that Cryptoki recognizes. It is defined + * as follows: */ +/* CK_OBJECT_CLASS was changed from CK_USHORT to CK_ULONG for + * v2.0 */ +typedef CK_ULONG CK_OBJECT_CLASS; + +/* The following classes of objects are defined: */ +/* CKO_HW_FEATURE is new for v2.10 */ +/* CKO_DOMAIN_PARAMETERS is new for v2.11 */ +#define CKO_DATA 0x00000000 +#define CKO_CERTIFICATE 0x00000001 +#define CKO_PUBLIC_KEY 0x00000002 +#define CKO_PRIVATE_KEY 0x00000003 +#define CKO_SECRET_KEY 0x00000004 +#define CKO_HW_FEATURE 0x00000005 +#define CKO_DOMAIN_PARAMETERS 0x00000006 +#define CKO_VENDOR_DEFINED 0x80000000 + +typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR; + +/* CK_HW_FEATURE_TYPE is new for v2.10. CK_HW_FEATURE_TYPE is a + * value that identifies the hardware feature type of an object + * with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */ +typedef CK_ULONG CK_HW_FEATURE_TYPE; + +/* The following hardware feature types are defined */ +#define CKH_MONOTONIC_COUNTER 0x00000001 +#define CKH_CLOCK 0x00000002 +#define CKH_VENDOR_DEFINED 0x80000000 + +/* CK_KEY_TYPE is a value that identifies a key type */ +/* CK_KEY_TYPE was changed from CK_USHORT to CK_ULONG for v2.0 */ +typedef CK_ULONG CK_KEY_TYPE; + +/* the following key types are defined: */ +#define CKK_RSA 0x00000000 +#define CKK_DSA 0x00000001 +#define CKK_DH 0x00000002 + +/* CKK_ECDSA and CKK_KEA are new for v2.0 */ +/* CKK_ECDSA is deprecated in v2.11, CKK_EC is preferred. */ +#define CKK_ECDSA 0x00000003 +#define CKK_EC 0x00000003 +#define CKK_X9_42_DH 0x00000004 +#define CKK_KEA 0x00000005 + +#define CKK_GENERIC_SECRET 0x00000010 +#define CKK_RC2 0x00000011 +#define CKK_RC4 0x00000012 +#define CKK_DES 0x00000013 +#define CKK_DES2 0x00000014 +#define CKK_DES3 0x00000015 + +/* all these key types are new for v2.0 */ +#define CKK_CAST 0x00000016 +#define CKK_CAST3 0x00000017 +/* CKK_CAST5 is deprecated in v2.11, CKK_CAST128 is preferred. */ +#define CKK_CAST5 0x00000018 +#define CKK_CAST128 0x00000018 +#define CKK_RC5 0x00000019 +#define CKK_IDEA 0x0000001A +#define CKK_SKIPJACK 0x0000001B +#define CKK_BATON 0x0000001C +#define CKK_JUNIPER 0x0000001D +#define CKK_CDMF 0x0000001E +#define CKK_AES 0x0000001F + +#define CKK_VENDOR_DEFINED 0x80000000 + + +/* CK_CERTIFICATE_TYPE is a value that identifies a certificate + * type */ +/* CK_CERTIFICATE_TYPE was changed from CK_USHORT to CK_ULONG + * for v2.0 */ +typedef CK_ULONG CK_CERTIFICATE_TYPE; + +/* The following certificate types are defined: */ +/* CKC_X_509_ATTR_CERT is new for v2.10 */ +#define CKC_X_509 0x00000000 +#define CKC_X_509_ATTR_CERT 0x00000001 +#define CKC_VENDOR_DEFINED 0x80000000 + + +/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute + * type */ +/* CK_ATTRIBUTE_TYPE was changed from CK_USHORT to CK_ULONG for + * v2.0 */ +typedef CK_ULONG CK_ATTRIBUTE_TYPE; + +/* The following attribute types are defined: */ +#define CKA_CLASS 0x00000000 +#define CKA_TOKEN 0x00000001 +#define CKA_PRIVATE 0x00000002 +#define CKA_LABEL 0x00000003 +#define CKA_APPLICATION 0x00000010 +#define CKA_VALUE 0x00000011 + +/* CKA_OBJECT_ID is new for v2.10 */ +#define CKA_OBJECT_ID 0x00000012 + +#define CKA_CERTIFICATE_TYPE 0x00000080 +#define CKA_ISSUER 0x00000081 +#define CKA_SERIAL_NUMBER 0x00000082 + +/* CKA_AC_ISSUER, CKA_OWNER, and CKA_ATTR_TYPES are new + * for v2.10 */ +#define CKA_AC_ISSUER 0x00000083 +#define CKA_OWNER 0x00000084 +#define CKA_ATTR_TYPES 0x00000085 + +/* CKA_TRUSTED is new for v2.11 */ +#define CKA_TRUSTED 0x00000086 + +#define CKA_KEY_TYPE 0x00000100 +#define CKA_SUBJECT 0x00000101 +#define CKA_ID 0x00000102 +#define CKA_SENSITIVE 0x00000103 +#define CKA_ENCRYPT 0x00000104 +#define CKA_DECRYPT 0x00000105 +#define CKA_WRAP 0x00000106 +#define CKA_UNWRAP 0x00000107 +#define CKA_SIGN 0x00000108 +#define CKA_SIGN_RECOVER 0x00000109 +#define CKA_VERIFY 0x0000010A +#define CKA_VERIFY_RECOVER 0x0000010B +#define CKA_DERIVE 0x0000010C +#define CKA_START_DATE 0x00000110 +#define CKA_END_DATE 0x00000111 +#define CKA_MODULUS 0x00000120 +#define CKA_MODULUS_BITS 0x00000121 +#define CKA_PUBLIC_EXPONENT 0x00000122 +#define CKA_PRIVATE_EXPONENT 0x00000123 +#define CKA_PRIME_1 0x00000124 +#define CKA_PRIME_2 0x00000125 +#define CKA_EXPONENT_1 0x00000126 +#define CKA_EXPONENT_2 0x00000127 +#define CKA_COEFFICIENT 0x00000128 +#define CKA_PRIME 0x00000130 +#define CKA_SUBPRIME 0x00000131 +#define CKA_BASE 0x00000132 + +/* CKA_PRIME_BITS and CKA_SUB_PRIME_BITS are new for v2.11 */ +#define CKA_PRIME_BITS 0x00000133 +#define CKA_SUBPRIME_BITS 0x00000134 +#define CKA_SUB_PRIME_BITS CKA_SUBPRIME_BITS +/* (To retain backwards-compatibility) */ + +#define CKA_VALUE_BITS 0x00000160 +#define CKA_VALUE_LEN 0x00000161 + +/* CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE, + * CKA_ALWAYS_SENSITIVE, CKA_MODIFIABLE, CKA_ECDSA_PARAMS, + * and CKA_EC_POINT are new for v2.0 */ +#define CKA_EXTRACTABLE 0x00000162 +#define CKA_LOCAL 0x00000163 +#define CKA_NEVER_EXTRACTABLE 0x00000164 +#define CKA_ALWAYS_SENSITIVE 0x00000165 + +/* CKA_KEY_GEN_MECHANISM is new for v2.11 */ +#define CKA_KEY_GEN_MECHANISM 0x00000166 + +#define CKA_MODIFIABLE 0x00000170 + +/* CKA_ECDSA_PARAMS is deprecated in v2.11, + * CKA_EC_PARAMS is preferred. */ +#define CKA_ECDSA_PARAMS 0x00000180 +#define CKA_EC_PARAMS 0x00000180 + +#define CKA_EC_POINT 0x00000181 + +/* CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, + * CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, and CKA_HAS_RESET + * are new for v2.10 */ +#define CKA_SECONDARY_AUTH 0x00000200 +#define CKA_AUTH_PIN_FLAGS 0x00000201 +#define CKA_HW_FEATURE_TYPE 0x00000300 +#define CKA_RESET_ON_INIT 0x00000301 +#define CKA_HAS_RESET 0x00000302 + +#define CKA_VENDOR_DEFINED 0x80000000 + + +/* CK_ATTRIBUTE is a structure that includes the type, length + * and value of an attribute */ +typedef struct CK_ATTRIBUTE { + CK_ATTRIBUTE_TYPE type; + CK_VOID_PTR pValue; + + /* ulValueLen went from CK_USHORT to CK_ULONG for v2.0 */ + CK_ULONG ulValueLen; /* in bytes */ +} CK_ATTRIBUTE; + +typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR; + + +/* CK_DATE is a structure that defines a date */ +typedef struct CK_DATE{ + CK_CHAR year[4]; /* the year ("1900" - "9999") */ + CK_CHAR month[2]; /* the month ("01" - "12") */ + CK_CHAR day[2]; /* the day ("01" - "31") */ +} CK_DATE; + + +/* CK_MECHANISM_TYPE is a value that identifies a mechanism + * type */ +/* CK_MECHANISM_TYPE was changed from CK_USHORT to CK_ULONG for + * v2.0 */ +typedef CK_ULONG CK_MECHANISM_TYPE; + +/* the following mechanism types are defined: */ +#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000 +#define CKM_RSA_PKCS 0x00000001 +#define CKM_RSA_9796 0x00000002 +#define CKM_RSA_X_509 0x00000003 + +/* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS + * are new for v2.0. They are mechanisms which hash and sign */ +#define CKM_MD2_RSA_PKCS 0x00000004 +#define CKM_MD5_RSA_PKCS 0x00000005 +#define CKM_SHA1_RSA_PKCS 0x00000006 + +/* CKM_RIPEMD128_RSA_PKCS, CKM_RIPEMD160_RSA_PKCS, and + * CKM_RSA_PKCS_OAEP are new for v2.10 */ +#define CKM_RIPEMD128_RSA_PKCS 0x00000007 +#define CKM_RIPEMD160_RSA_PKCS 0x00000008 +#define CKM_RSA_PKCS_OAEP 0x00000009 + +/* CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, CKM_SHA1_RSA_X9_31, + * CKM_RSA_PKCS_PSS, and CKM_SHA1_RSA_PKCS_PSS are new for v2.11 */ +#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000A +#define CKM_RSA_X9_31 0x0000000B +#define CKM_SHA1_RSA_X9_31 0x0000000C +#define CKM_RSA_PKCS_PSS 0x0000000D +#define CKM_SHA1_RSA_PKCS_PSS 0x0000000E + +#define CKM_DSA_KEY_PAIR_GEN 0x00000010 +#define CKM_DSA 0x00000011 +#define CKM_DSA_SHA1 0x00000012 +#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020 +#define CKM_DH_PKCS_DERIVE 0x00000021 + +/* CKM_X9_42_DH_KEY_PAIR_GEN, CKM_X9_42_DH_DERIVE, + * CKM_X9_42_DH_HYBRID_DERIVE, and CKM_X9_42_MQV_DERIVE are new for + * v2.11 */ +#define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030 +#define CKM_X9_42_DH_DERIVE 0x00000031 +#define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032 +#define CKM_X9_42_MQV_DERIVE 0x00000033 + +#define CKM_RC2_KEY_GEN 0x00000100 +#define CKM_RC2_ECB 0x00000101 +#define CKM_RC2_CBC 0x00000102 +#define CKM_RC2_MAC 0x00000103 + +/* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new for v2.0 */ +#define CKM_RC2_MAC_GENERAL 0x00000104 +#define CKM_RC2_CBC_PAD 0x00000105 + +#define CKM_RC4_KEY_GEN 0x00000110 +#define CKM_RC4 0x00000111 +#define CKM_DES_KEY_GEN 0x00000120 +#define CKM_DES_ECB 0x00000121 +#define CKM_DES_CBC 0x00000122 +#define CKM_DES_MAC 0x00000123 + +/* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new for v2.0 */ +#define CKM_DES_MAC_GENERAL 0x00000124 +#define CKM_DES_CBC_PAD 0x00000125 + +#define CKM_DES2_KEY_GEN 0x00000130 +#define CKM_DES3_KEY_GEN 0x00000131 +#define CKM_DES3_ECB 0x00000132 +#define CKM_DES3_CBC 0x00000133 +#define CKM_DES3_MAC 0x00000134 + +/* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN, + * CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC, + * CKM_CDMF_MAC_GENERAL, and CKM_CDMF_CBC_PAD are new for v2.0 */ +#define CKM_DES3_MAC_GENERAL 0x00000135 +#define CKM_DES3_CBC_PAD 0x00000136 +#define CKM_CDMF_KEY_GEN 0x00000140 +#define CKM_CDMF_ECB 0x00000141 +#define CKM_CDMF_CBC 0x00000142 +#define CKM_CDMF_MAC 0x00000143 +#define CKM_CDMF_MAC_GENERAL 0x00000144 +#define CKM_CDMF_CBC_PAD 0x00000145 + +#define CKM_MD2 0x00000200 + +/* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new for v2.0 */ +#define CKM_MD2_HMAC 0x00000201 +#define CKM_MD2_HMAC_GENERAL 0x00000202 + +#define CKM_MD5 0x00000210 + +/* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new for v2.0 */ +#define CKM_MD5_HMAC 0x00000211 +#define CKM_MD5_HMAC_GENERAL 0x00000212 + +#define CKM_SHA_1 0x00000220 + +/* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new for v2.0 */ +#define CKM_SHA_1_HMAC 0x00000221 +#define CKM_SHA_1_HMAC_GENERAL 0x00000222 + +/* CKM_RIPEMD128, CKM_RIPEMD128_HMAC, + * CKM_RIPEMD128_HMAC_GENERAL, CKM_RIPEMD160, CKM_RIPEMD160_HMAC, + * and CKM_RIPEMD160_HMAC_GENERAL are new for v2.10 */ +#define CKM_RIPEMD128 0x00000230 +#define CKM_RIPEMD128_HMAC 0x00000231 +#define CKM_RIPEMD128_HMAC_GENERAL 0x00000232 +#define CKM_RIPEMD160 0x00000240 +#define CKM_RIPEMD160_HMAC 0x00000241 +#define CKM_RIPEMD160_HMAC_GENERAL 0x00000242 + +/* All of the following mechanisms are new for v2.0 */ +/* Note that CAST128 and CAST5 are the same algorithm */ +#define CKM_CAST_KEY_GEN 0x00000300 +#define CKM_CAST_ECB 0x00000301 +#define CKM_CAST_CBC 0x00000302 +#define CKM_CAST_MAC 0x00000303 +#define CKM_CAST_MAC_GENERAL 0x00000304 +#define CKM_CAST_CBC_PAD 0x00000305 +#define CKM_CAST3_KEY_GEN 0x00000310 +#define CKM_CAST3_ECB 0x00000311 +#define CKM_CAST3_CBC 0x00000312 +#define CKM_CAST3_MAC 0x00000313 +#define CKM_CAST3_MAC_GENERAL 0x00000314 +#define CKM_CAST3_CBC_PAD 0x00000315 +#define CKM_CAST5_KEY_GEN 0x00000320 +#define CKM_CAST128_KEY_GEN 0x00000320 +#define CKM_CAST5_ECB 0x00000321 +#define CKM_CAST128_ECB 0x00000321 +#define CKM_CAST5_CBC 0x00000322 +#define CKM_CAST128_CBC 0x00000322 +#define CKM_CAST5_MAC 0x00000323 +#define CKM_CAST128_MAC 0x00000323 +#define CKM_CAST5_MAC_GENERAL 0x00000324 +#define CKM_CAST128_MAC_GENERAL 0x00000324 +#define CKM_CAST5_CBC_PAD 0x00000325 +#define CKM_CAST128_CBC_PAD 0x00000325 +#define CKM_RC5_KEY_GEN 0x00000330 +#define CKM_RC5_ECB 0x00000331 +#define CKM_RC5_CBC 0x00000332 +#define CKM_RC5_MAC 0x00000333 +#define CKM_RC5_MAC_GENERAL 0x00000334 +#define CKM_RC5_CBC_PAD 0x00000335 +#define CKM_IDEA_KEY_GEN 0x00000340 +#define CKM_IDEA_ECB 0x00000341 +#define CKM_IDEA_CBC 0x00000342 +#define CKM_IDEA_MAC 0x00000343 +#define CKM_IDEA_MAC_GENERAL 0x00000344 +#define CKM_IDEA_CBC_PAD 0x00000345 +#define CKM_GENERIC_SECRET_KEY_GEN 0x00000350 +#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360 +#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362 +#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363 +#define CKM_XOR_BASE_AND_DATA 0x00000364 +#define CKM_EXTRACT_KEY_FROM_KEY 0x00000365 +#define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370 +#define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371 +#define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372 + +/* CKM_SSL3_MASTER_KEY_DERIVE_DH, CKM_TLS_PRE_MASTER_KEY_GEN, + * CKM_TLS_MASTER_KEY_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE, and + * CKM_TLS_MASTER_KEY_DERIVE_DH are new for v2.11 */ +#define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373 +#define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374 +#define CKM_TLS_MASTER_KEY_DERIVE 0x00000375 +#define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376 +#define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377 + +#define CKM_SSL3_MD5_MAC 0x00000380 +#define CKM_SSL3_SHA1_MAC 0x00000381 +#define CKM_MD5_KEY_DERIVATION 0x00000390 +#define CKM_MD2_KEY_DERIVATION 0x00000391 +#define CKM_SHA1_KEY_DERIVATION 0x00000392 +#define CKM_PBE_MD2_DES_CBC 0x000003A0 +#define CKM_PBE_MD5_DES_CBC 0x000003A1 +#define CKM_PBE_MD5_CAST_CBC 0x000003A2 +#define CKM_PBE_MD5_CAST3_CBC 0x000003A3 +#define CKM_PBE_MD5_CAST5_CBC 0x000003A4 +#define CKM_PBE_MD5_CAST128_CBC 0x000003A4 +#define CKM_PBE_SHA1_CAST5_CBC 0x000003A5 +#define CKM_PBE_SHA1_CAST128_CBC 0x000003A5 +#define CKM_PBE_SHA1_RC4_128 0x000003A6 +#define CKM_PBE_SHA1_RC4_40 0x000003A7 +#define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8 +#define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9 +#define CKM_PBE_SHA1_RC2_128_CBC 0x000003AA +#define CKM_PBE_SHA1_RC2_40_CBC 0x000003AB + +/* CKM_PKCS5_PBKD2 is new for v2.10 */ +#define CKM_PKCS5_PBKD2 0x000003B0 + +#define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0 +#define CKM_KEY_WRAP_LYNKS 0x00000400 +#define CKM_KEY_WRAP_SET_OAEP 0x00000401 + +/* Fortezza mechanisms */ +#define CKM_SKIPJACK_KEY_GEN 0x00001000 +#define CKM_SKIPJACK_ECB64 0x00001001 +#define CKM_SKIPJACK_CBC64 0x00001002 +#define CKM_SKIPJACK_OFB64 0x00001003 +#define CKM_SKIPJACK_CFB64 0x00001004 +#define CKM_SKIPJACK_CFB32 0x00001005 +#define CKM_SKIPJACK_CFB16 0x00001006 +#define CKM_SKIPJACK_CFB8 0x00001007 +#define CKM_SKIPJACK_WRAP 0x00001008 +#define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009 +#define CKM_SKIPJACK_RELAYX 0x0000100a +#define CKM_KEA_KEY_PAIR_GEN 0x00001010 +#define CKM_KEA_KEY_DERIVE 0x00001011 +#define CKM_FORTEZZA_TIMESTAMP 0x00001020 +#define CKM_BATON_KEY_GEN 0x00001030 +#define CKM_BATON_ECB128 0x00001031 +#define CKM_BATON_ECB96 0x00001032 +#define CKM_BATON_CBC128 0x00001033 +#define CKM_BATON_COUNTER 0x00001034 +#define CKM_BATON_SHUFFLE 0x00001035 +#define CKM_BATON_WRAP 0x00001036 + +/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11, + * CKM_EC_KEY_PAIR_GEN is preferred */ +#define CKM_ECDSA_KEY_PAIR_GEN 0x00001040 +#define CKM_EC_KEY_PAIR_GEN 0x00001040 + +#define CKM_ECDSA 0x00001041 +#define CKM_ECDSA_SHA1 0x00001042 + +/* CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and CKM_ECMQV_DERIVE + * are new for v2.11 */ +#define CKM_ECDH1_DERIVE 0x00001050 +#define CKM_ECDH1_COFACTOR_DERIVE 0x00001051 +#define CKM_ECMQV_DERIVE 0x00001052 + +#define CKM_JUNIPER_KEY_GEN 0x00001060 +#define CKM_JUNIPER_ECB128 0x00001061 +#define CKM_JUNIPER_CBC128 0x00001062 +#define CKM_JUNIPER_COUNTER 0x00001063 +#define CKM_JUNIPER_SHUFFLE 0x00001064 +#define CKM_JUNIPER_WRAP 0x00001065 +#define CKM_FASTHASH 0x00001070 + +/* CKM_AES_KEY_GEN, CKM_AES_ECB, CKM_AES_CBC, CKM_AES_MAC, + * CKM_AES_MAC_GENERAL, CKM_AES_CBC_PAD, CKM_DSA_PARAMETER_GEN, + * CKM_DH_PKCS_PARAMETER_GEN, and CKM_X9_42_DH_PARAMETER_GEN are + * new for v2.11 */ +#define CKM_AES_KEY_GEN 0x00001080 +#define CKM_AES_ECB 0x00001081 +#define CKM_AES_CBC 0x00001082 +#define CKM_AES_MAC 0x00001083 +#define CKM_AES_MAC_GENERAL 0x00001084 +#define CKM_AES_CBC_PAD 0x00001085 +#define CKM_DSA_PARAMETER_GEN 0x00002000 +#define CKM_DH_PKCS_PARAMETER_GEN 0x00002001 +#define CKM_X9_42_DH_PARAMETER_GEN 0x00002002 + +#define CKM_VENDOR_DEFINED 0x80000000 + +typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR; + + +/* CK_MECHANISM is a structure that specifies a particular + * mechanism */ +typedef struct CK_MECHANISM { + CK_MECHANISM_TYPE mechanism; + CK_VOID_PTR pParameter; + + /* ulParameterLen was changed from CK_USHORT to CK_ULONG for + * v2.0 */ + CK_ULONG ulParameterLen; /* in bytes */ +} CK_MECHANISM; + +typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR; + + +/* CK_MECHANISM_INFO provides information about a particular + * mechanism */ +typedef struct CK_MECHANISM_INFO { + CK_ULONG ulMinKeySize; + CK_ULONG ulMaxKeySize; + CK_FLAGS flags; +} CK_MECHANISM_INFO; + +/* The flags are defined as follows: + * Bit Flag Mask Meaning */ +#define CKF_HW 0x00000001 /* performed by HW */ + +/* The flags CKF_ENCRYPT, CKF_DECRYPT, CKF_DIGEST, CKF_SIGN, + * CKG_SIGN_RECOVER, CKF_VERIFY, CKF_VERIFY_RECOVER, + * CKF_GENERATE, CKF_GENERATE_KEY_PAIR, CKF_WRAP, CKF_UNWRAP, + * and CKF_DERIVE are new for v2.0. They specify whether or not + * a mechanism can be used for a particular task */ +#define CKF_ENCRYPT 0x00000100 +#define CKF_DECRYPT 0x00000200 +#define CKF_DIGEST 0x00000400 +#define CKF_SIGN 0x00000800 +#define CKF_SIGN_RECOVER 0x00001000 +#define CKF_VERIFY 0x00002000 +#define CKF_VERIFY_RECOVER 0x00004000 +#define CKF_GENERATE 0x00008000 +#define CKF_GENERATE_KEY_PAIR 0x00010000 +#define CKF_WRAP 0x00020000 +#define CKF_UNWRAP 0x00040000 +#define CKF_DERIVE 0x00080000 + +/* CKF_EC_F_P, CKF_EC_F_2M, CKF_EC_ECPARAMETERS, CKF_EC_NAMEDCURVE, + * CKF_EC_UNCOMPRESS, and CKF_EC_COMPRESS are new for v2.11. They + * describe a token's EC capabilities not available in mechanism + * information. */ +#define CKF_EC_F_P 0x00100000 +#define CKF_EC_F_2M 0x00200000 +#define CKF_EC_ECPARAMETERS 0x00400000 +#define CKF_EC_NAMEDCURVE 0x00800000 +#define CKF_EC_UNCOMPRESS 0x01000000 +#define CKF_EC_COMPRESS 0x02000000 + +#define CKF_EXTENSION 0x80000000 /* FALSE for 2.01 */ + +typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR; + + +/* CK_RV is a value that identifies the return value of a + * Cryptoki function */ +/* CK_RV was changed from CK_USHORT to CK_ULONG for v2.0 */ +typedef CK_ULONG CK_RV; + +#define CKR_OK 0x00000000 +#define CKR_CANCEL 0x00000001 +#define CKR_HOST_MEMORY 0x00000002 +#define CKR_SLOT_ID_INVALID 0x00000003 + +/* CKR_FLAGS_INVALID was removed for v2.0 */ + +/* CKR_GENERAL_ERROR and CKR_FUNCTION_FAILED are new for v2.0 */ +#define CKR_GENERAL_ERROR 0x00000005 +#define CKR_FUNCTION_FAILED 0x00000006 + +/* CKR_ARGUMENTS_BAD, CKR_NO_EVENT, CKR_NEED_TO_CREATE_THREADS, + * and CKR_CANT_LOCK are new for v2.01 */ +#define CKR_ARGUMENTS_BAD 0x00000007 +#define CKR_NO_EVENT 0x00000008 +#define CKR_NEED_TO_CREATE_THREADS 0x00000009 +#define CKR_CANT_LOCK 0x0000000A + +#define CKR_ATTRIBUTE_READ_ONLY 0x00000010 +#define CKR_ATTRIBUTE_SENSITIVE 0x00000011 +#define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012 +#define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013 +#define CKR_DATA_INVALID 0x00000020 +#define CKR_DATA_LEN_RANGE 0x00000021 +#define CKR_DEVICE_ERROR 0x00000030 +#define CKR_DEVICE_MEMORY 0x00000031 +#define CKR_DEVICE_REMOVED 0x00000032 +#define CKR_ENCRYPTED_DATA_INVALID 0x00000040 +#define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041 +#define CKR_FUNCTION_CANCELED 0x00000050 +#define CKR_FUNCTION_NOT_PARALLEL 0x00000051 + +/* CKR_FUNCTION_NOT_SUPPORTED is new for v2.0 */ +#define CKR_FUNCTION_NOT_SUPPORTED 0x00000054 + +#define CKR_KEY_HANDLE_INVALID 0x00000060 + +/* CKR_KEY_SENSITIVE was removed for v2.0 */ + +#define CKR_KEY_SIZE_RANGE 0x00000062 +#define CKR_KEY_TYPE_INCONSISTENT 0x00000063 + +/* CKR_KEY_NOT_NEEDED, CKR_KEY_CHANGED, CKR_KEY_NEEDED, + * CKR_KEY_INDIGESTIBLE, CKR_KEY_FUNCTION_NOT_PERMITTED, + * CKR_KEY_NOT_WRAPPABLE, and CKR_KEY_UNEXTRACTABLE are new for + * v2.0 */ +#define CKR_KEY_NOT_NEEDED 0x00000064 +#define CKR_KEY_CHANGED 0x00000065 +#define CKR_KEY_NEEDED 0x00000066 +#define CKR_KEY_INDIGESTIBLE 0x00000067 +#define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068 +#define CKR_KEY_NOT_WRAPPABLE 0x00000069 +#define CKR_KEY_UNEXTRACTABLE 0x0000006A + +#define CKR_MECHANISM_INVALID 0x00000070 +#define CKR_MECHANISM_PARAM_INVALID 0x00000071 + +/* CKR_OBJECT_CLASS_INCONSISTENT and CKR_OBJECT_CLASS_INVALID + * were removed for v2.0 */ +#define CKR_OBJECT_HANDLE_INVALID 0x00000082 +#define CKR_OPERATION_ACTIVE 0x00000090 +#define CKR_OPERATION_NOT_INITIALIZED 0x00000091 +#define CKR_PIN_INCORRECT 0x000000A0 +#define CKR_PIN_INVALID 0x000000A1 +#define CKR_PIN_LEN_RANGE 0x000000A2 + +/* CKR_PIN_EXPIRED and CKR_PIN_LOCKED are new for v2.0 */ +#define CKR_PIN_EXPIRED 0x000000A3 +#define CKR_PIN_LOCKED 0x000000A4 + +#define CKR_SESSION_CLOSED 0x000000B0 +#define CKR_SESSION_COUNT 0x000000B1 +#define CKR_SESSION_HANDLE_INVALID 0x000000B3 +#define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4 +#define CKR_SESSION_READ_ONLY 0x000000B5 +#define CKR_SESSION_EXISTS 0x000000B6 + +/* CKR_SESSION_READ_ONLY_EXISTS and + * CKR_SESSION_READ_WRITE_SO_EXISTS are new for v2.0 */ +#define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7 +#define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8 + +#define CKR_SIGNATURE_INVALID 0x000000C0 +#define CKR_SIGNATURE_LEN_RANGE 0x000000C1 +#define CKR_TEMPLATE_INCOMPLETE 0x000000D0 +#define CKR_TEMPLATE_INCONSISTENT 0x000000D1 +#define CKR_TOKEN_NOT_PRESENT 0x000000E0 +#define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1 +#define CKR_TOKEN_WRITE_PROTECTED 0x000000E2 +#define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0 +#define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1 +#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2 +#define CKR_USER_ALREADY_LOGGED_IN 0x00000100 +#define CKR_USER_NOT_LOGGED_IN 0x00000101 +#define CKR_USER_PIN_NOT_INITIALIZED 0x00000102 +#define CKR_USER_TYPE_INVALID 0x00000103 + +/* CKR_USER_ANOTHER_ALREADY_LOGGED_IN and CKR_USER_TOO_MANY_TYPES + * are new to v2.01 */ +#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104 +#define CKR_USER_TOO_MANY_TYPES 0x00000105 + +#define CKR_WRAPPED_KEY_INVALID 0x00000110 +#define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112 +#define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113 +#define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114 +#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115 +#define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120 + +/* These are new to v2.0 */ +#define CKR_RANDOM_NO_RNG 0x00000121 + +/* These are new to v2.11 */ +#define CKR_DOMAIN_PARAMS_INVALID 0x00000130 + +/* These are new to v2.0 */ +#define CKR_BUFFER_TOO_SMALL 0x00000150 +#define CKR_SAVED_STATE_INVALID 0x00000160 +#define CKR_INFORMATION_SENSITIVE 0x00000170 +#define CKR_STATE_UNSAVEABLE 0x00000180 + +/* These are new to v2.01 */ +#define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190 +#define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191 +#define CKR_MUTEX_BAD 0x000001A0 +#define CKR_MUTEX_NOT_LOCKED 0x000001A1 + +#define CKR_VENDOR_DEFINED 0x80000000 + + +/* CK_NOTIFY is an application callback that processes events */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_NOTIFICATION event, + CK_VOID_PTR pApplication /* passed to C_OpenSession */ +); + + +/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec + * version and pointers of appropriate types to all the + * Cryptoki functions */ +/* CK_FUNCTION_LIST is new for v2.0 */ +typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST; + +typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR; + +typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR; + + +/* CK_CREATEMUTEX is an application callback for creating a + * mutex object */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)( + CK_VOID_PTR_PTR ppMutex /* location to receive ptr to mutex */ +); + + +/* CK_DESTROYMUTEX is an application callback for destroying a + * mutex object */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)( + CK_VOID_PTR pMutex /* pointer to mutex */ +); + + +/* CK_LOCKMUTEX is an application callback for locking a mutex */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)( + CK_VOID_PTR pMutex /* pointer to mutex */ +); + + +/* CK_UNLOCKMUTEX is an application callback for unlocking a + * mutex */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)( + CK_VOID_PTR pMutex /* pointer to mutex */ +); + + +/* CK_C_INITIALIZE_ARGS provides the optional arguments to + * C_Initialize */ +typedef struct CK_C_INITIALIZE_ARGS { + CK_CREATEMUTEX CreateMutex; + CK_DESTROYMUTEX DestroyMutex; + CK_LOCKMUTEX LockMutex; + CK_UNLOCKMUTEX UnlockMutex; + CK_FLAGS flags; + CK_VOID_PTR pReserved; +} CK_C_INITIALIZE_ARGS; + +/* flags: bit flags that provide capabilities of the slot + * Bit Flag Mask Meaning + */ +#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001 +#define CKF_OS_LOCKING_OK 0x00000002 + +typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR; + + +/* additional flags for parameters to functions */ + +/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */ +#define CKF_DONT_BLOCK 1 + +/* CK_RSA_PKCS_OAEP_MGF_TYPE is new for v2.10. + * CK_RSA_PKCS_OAEP_MGF_TYPE is used to indicate the Message + * Generation Function (MGF) applied to a message block when + * formatting a message block for the PKCS #1 OAEP encryption + * scheme. */ +typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE; + +typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR; + +/* The following MGFs are defined */ +#define CKG_MGF1_SHA1 0x00000001 + +/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is new for v2.10. + * CK_RSA_PKCS_OAEP_SOURCE_TYPE is used to indicate the source + * of the encoding parameter when formatting a message block + * for the PKCS #1 OAEP encryption scheme. */ +typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE; + +typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR; + +/* The following encoding parameter sources are defined */ +#define CKZ_DATA_SPECIFIED 0x00000001 + +/* CK_RSA_PKCS_OAEP_PARAMS is new for v2.10. + * CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the + * CKM_RSA_PKCS_OAEP mechanism. */ +typedef struct CK_RSA_PKCS_OAEP_PARAMS { + CK_MECHANISM_TYPE hashAlg; + CK_RSA_PKCS_MGF_TYPE mgf; + CK_RSA_PKCS_OAEP_SOURCE_TYPE source; + CK_VOID_PTR pSourceData; + CK_ULONG ulSourceDataLen; +} CK_RSA_PKCS_OAEP_PARAMS; + +typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR; + +/* CK_RSA_PKCS_PSS_PARAMS is new for v2.11. + * CK_RSA_PKCS_PSS_PARAMS provides the parameters to the + * CKM_RSA_PKCS_PSS mechanism(s). */ +typedef struct CK_RSA_PKCS_PSS_PARAMS { + CK_MECHANISM_TYPE hashAlg; + CK_RSA_PKCS_MGF_TYPE mgf; + CK_ULONG sLen; +} CK_RSA_PKCS_PSS_PARAMS; + +typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR; + +/* CK_EC_KDF_TYPE is new for v2.11. */ +typedef CK_ULONG CK_EC_KDF_TYPE; + +/* The following EC Key Derivation Functions are defined */ +#define CKD_NULL 0x00000001 +#define CKD_SHA1_KDF 0x00000002 + +/* CK_ECDH1_DERIVE_PARAMS is new for v2.11. + * CK_ECDH1_DERIVE_PARAMS provides the parameters to the + * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms, + * where each party contributes one key pair. + */ +typedef struct CK_ECDH1_DERIVE_PARAMS { + CK_EC_KDF_TYPE kdf; + CK_ULONG ulSharedDataLen; + CK_BYTE_PTR pSharedData; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; +} CK_ECDH1_DERIVE_PARAMS; + +typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR; + + +/* CK_ECDH2_DERIVE_PARAMS is new for v2.11. + * CK_ECDH2_DERIVE_PARAMS provides the parameters to the + * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs. */ +typedef struct CK_ECDH2_DERIVE_PARAMS { + CK_EC_KDF_TYPE kdf; + CK_ULONG ulSharedDataLen; + CK_BYTE_PTR pSharedData; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; + CK_ULONG ulPrivateDataLen; + CK_OBJECT_HANDLE hPrivateData; + CK_ULONG ulPublicDataLen2; + CK_BYTE_PTR pPublicData2; +} CK_ECDH2_DERIVE_PARAMS; + +typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR; + +/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the + * CKM_X9_42_DH_PARAMETER_GEN mechanisms (new for PKCS #11 v2.11) */ +typedef CK_ULONG CK_X9_42_DH_KDF_TYPE; +typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR; + +/* The following X9.42 DH key derivation functions are defined: */ +#define CKD_NULL 0x00000001 +#define CKD_SHA1_KDF_ASN1 0x00000003 +#define CKD_SHA1_KDF_CONCATENATE 0x00000004 + +/* CK_X9_42_DH1_DERIVE_PARAMS is new for v2.11. + * CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the + * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party + * contributes one key pair */ +typedef struct CK_X9_42_DH1_DERIVE_PARAMS { + CK_X9_42_DH_KDF_TYPE kdf; + CK_ULONG ulOtherInfoLen; + CK_BYTE_PTR pOtherInfo; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; +} CK_X9_42_DH1_DERIVE_PARAMS; + +typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR; + +/* CK_X9_42_DH2_DERIVE_PARAMS is new for v2.11. + * CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the + * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation + * mechanisms, where each party contributes two key pairs */ +typedef struct CK_X9_42_DH2_DERIVE_PARAMS { + CK_X9_42_DH_KDF_TYPE kdf; + CK_ULONG ulOtherInfoLen; + CK_BYTE_PTR pOtherInfo; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; + CK_ULONG ulPrivateDataLen; + CK_OBJECT_HANDLE hPrivateData; + CK_ULONG ulPublicDataLen2; + CK_BYTE_PTR pPublicData2; +} CK_X9_42_DH2_DERIVE_PARAMS; + +typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR; + +/* CK_KEA_DERIVE_PARAMS provides the parameters to the + * CKM_KEA_DERIVE mechanism */ +/* CK_KEA_DERIVE_PARAMS is new for v2.0 */ +typedef struct CK_KEA_DERIVE_PARAMS { + CK_BBOOL isSender; + CK_ULONG ulRandomLen; + CK_BYTE_PTR pRandomA; + CK_BYTE_PTR pRandomB; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; +} CK_KEA_DERIVE_PARAMS; + +typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR; + + +/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and + * CKM_RC2_MAC mechanisms. An instance of CK_RC2_PARAMS just + * holds the effective keysize */ +typedef CK_ULONG CK_RC2_PARAMS; + +typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR; + + +/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC + * mechanism */ +typedef struct CK_RC2_CBC_PARAMS { + /* ulEffectiveBits was changed from CK_USHORT to CK_ULONG for + * v2.0 */ + CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */ + + CK_BYTE iv[8]; /* IV for CBC mode */ +} CK_RC2_CBC_PARAMS; + +typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR; + + +/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the + * CKM_RC2_MAC_GENERAL mechanism */ +/* CK_RC2_MAC_GENERAL_PARAMS is new for v2.0 */ +typedef struct CK_RC2_MAC_GENERAL_PARAMS { + CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */ + CK_ULONG ulMacLength; /* Length of MAC in bytes */ +} CK_RC2_MAC_GENERAL_PARAMS; + +typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \ + CK_RC2_MAC_GENERAL_PARAMS_PTR; + + +/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and + * CKM_RC5_MAC mechanisms */ +/* CK_RC5_PARAMS is new for v2.0 */ +typedef struct CK_RC5_PARAMS { + CK_ULONG ulWordsize; /* wordsize in bits */ + CK_ULONG ulRounds; /* number of rounds */ +} CK_RC5_PARAMS; + +typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR; + + +/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC + * mechanism */ +/* CK_RC5_CBC_PARAMS is new for v2.0 */ +typedef struct CK_RC5_CBC_PARAMS { + CK_ULONG ulWordsize; /* wordsize in bits */ + CK_ULONG ulRounds; /* number of rounds */ + CK_BYTE_PTR pIv; /* pointer to IV */ + CK_ULONG ulIvLen; /* length of IV in bytes */ +} CK_RC5_CBC_PARAMS; + +typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR; + + +/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the + * CKM_RC5_MAC_GENERAL mechanism */ +/* CK_RC5_MAC_GENERAL_PARAMS is new for v2.0 */ +typedef struct CK_RC5_MAC_GENERAL_PARAMS { + CK_ULONG ulWordsize; /* wordsize in bits */ + CK_ULONG ulRounds; /* number of rounds */ + CK_ULONG ulMacLength; /* Length of MAC in bytes */ +} CK_RC5_MAC_GENERAL_PARAMS; + +typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \ + CK_RC5_MAC_GENERAL_PARAMS_PTR; + + +/* CK_MAC_GENERAL_PARAMS provides the parameters to most block + * ciphers' MAC_GENERAL mechanisms. Its value is the length of + * the MAC */ +/* CK_MAC_GENERAL_PARAMS is new for v2.0 */ +typedef CK_ULONG CK_MAC_GENERAL_PARAMS; + +typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR; + + +/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the + * CKM_SKIPJACK_PRIVATE_WRAP mechanism */ +/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS is new for v2.0 */ +typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS { + CK_ULONG ulPasswordLen; + CK_BYTE_PTR pPassword; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; + CK_ULONG ulPAndGLen; + CK_ULONG ulQLen; + CK_ULONG ulRandomLen; + CK_BYTE_PTR pRandomA; + CK_BYTE_PTR pPrimeP; + CK_BYTE_PTR pBaseG; + CK_BYTE_PTR pSubprimeQ; +} CK_SKIPJACK_PRIVATE_WRAP_PARAMS; + +typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \ + CK_SKIPJACK_PRIVATE_WRAP_PTR; + + +/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the + * CKM_SKIPJACK_RELAYX mechanism */ +/* CK_SKIPJACK_RELAYX_PARAMS is new for v2.0 */ +typedef struct CK_SKIPJACK_RELAYX_PARAMS { + CK_ULONG ulOldWrappedXLen; + CK_BYTE_PTR pOldWrappedX; + CK_ULONG ulOldPasswordLen; + CK_BYTE_PTR pOldPassword; + CK_ULONG ulOldPublicDataLen; + CK_BYTE_PTR pOldPublicData; + CK_ULONG ulOldRandomLen; + CK_BYTE_PTR pOldRandomA; + CK_ULONG ulNewPasswordLen; + CK_BYTE_PTR pNewPassword; + CK_ULONG ulNewPublicDataLen; + CK_BYTE_PTR pNewPublicData; + CK_ULONG ulNewRandomLen; + CK_BYTE_PTR pNewRandomA; +} CK_SKIPJACK_RELAYX_PARAMS; + +typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \ + CK_SKIPJACK_RELAYX_PARAMS_PTR; + + +typedef struct CK_PBE_PARAMS { + CK_BYTE_PTR pInitVector; + CK_UTF8CHAR_PTR pPassword; + CK_ULONG ulPasswordLen; + CK_BYTE_PTR pSalt; + CK_ULONG ulSaltLen; + CK_ULONG ulIteration; +} CK_PBE_PARAMS; + +typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR; + + +/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the + * CKM_KEY_WRAP_SET_OAEP mechanism */ +/* CK_KEY_WRAP_SET_OAEP_PARAMS is new for v2.0 */ +typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS { + CK_BYTE bBC; /* block contents byte */ + CK_BYTE_PTR pX; /* extra data */ + CK_ULONG ulXLen; /* length of extra data in bytes */ +} CK_KEY_WRAP_SET_OAEP_PARAMS; + +typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR \ + CK_KEY_WRAP_SET_OAEP_PARAMS_PTR; + + +typedef struct CK_SSL3_RANDOM_DATA { + CK_BYTE_PTR pClientRandom; + CK_ULONG ulClientRandomLen; + CK_BYTE_PTR pServerRandom; + CK_ULONG ulServerRandomLen; +} CK_SSL3_RANDOM_DATA; + + +typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS { + CK_SSL3_RANDOM_DATA RandomInfo; + CK_VERSION_PTR pVersion; +} CK_SSL3_MASTER_KEY_DERIVE_PARAMS; + +typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \ + CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR; + + +typedef struct CK_SSL3_KEY_MAT_OUT { + CK_OBJECT_HANDLE hClientMacSecret; + CK_OBJECT_HANDLE hServerMacSecret; + CK_OBJECT_HANDLE hClientKey; + CK_OBJECT_HANDLE hServerKey; + CK_BYTE_PTR pIVClient; + CK_BYTE_PTR pIVServer; +} CK_SSL3_KEY_MAT_OUT; + +typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR; + + +typedef struct CK_SSL3_KEY_MAT_PARAMS { + CK_ULONG ulMacSizeInBits; + CK_ULONG ulKeySizeInBits; + CK_ULONG ulIVSizeInBits; + CK_BBOOL bIsExport; + CK_SSL3_RANDOM_DATA RandomInfo; + CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial; +} CK_SSL3_KEY_MAT_PARAMS; + +typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR; + + +typedef struct CK_KEY_DERIVATION_STRING_DATA { + CK_BYTE_PTR pData; + CK_ULONG ulLen; +} CK_KEY_DERIVATION_STRING_DATA; + +typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \ + CK_KEY_DERIVATION_STRING_DATA_PTR; + + +/* The CK_EXTRACT_PARAMS is used for the + * CKM_EXTRACT_KEY_FROM_KEY mechanism. It specifies which bit + * of the base key should be used as the first bit of the + * derived key */ +/* CK_EXTRACT_PARAMS is new for v2.0 */ +typedef CK_ULONG CK_EXTRACT_PARAMS; + +typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR; + +/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is new for v2.10. + * CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to + * indicate the Pseudo-Random Function (PRF) used to generate + * key bits using PKCS #5 PBKDF2. */ +typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE; + +typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR; + +/* The following PRFs are defined in PKCS #5 v2.0. */ +#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001 + + +/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is new for v2.10. + * CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the + * source of the salt value when deriving a key using PKCS #5 + * PBKDF2. */ +typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE; + +typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR; + +/* The following salt value sources are defined in PKCS #5 v2.0. */ +#define CKZ_SALT_SPECIFIED 0x00000001 + +/* CK_PKCS5_PBKD2_PARAMS is new for v2.10. + * CK_PKCS5_PBKD2_PARAMS is a structure that provides the + * parameters to the CKM_PKCS5_PBKD2 mechanism. */ +typedef struct CK_PKCS5_PBKD2_PARAMS { + CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource; + CK_VOID_PTR pSaltSourceData; + CK_ULONG ulSaltSourceDataLen; + CK_ULONG iterations; + CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf; + CK_VOID_PTR pPrfData; + CK_ULONG ulPrfDataLen; + CK_UTF8CHAR_PTR pPassword; + CK_ULONG_PTR ulPasswordLen; +} CK_PKCS5_PBKD2_PARAMS; + +typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR; + +#endif diff --git a/lib/hx509/ref/pkcs11u.h b/lib/hx509/ref/pkcs11u.h new file mode 100644 index 000000000..328cce707 --- /dev/null +++ b/lib/hx509/ref/pkcs11u.h @@ -0,0 +1,21 @@ + +/* unix version adaption file */ + +#define CK_PTR * + +#define CK_DEFINE_FUNCTION(returnType, name) \ + returnType name + +#define CK_DECLARE_FUNCTION(returnType, name) \ + returnType name + +#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ + returnType (* name) + +#define CK_CALLBACK_FUNCTION(returnType, name) \ + returnType (* name) + +#ifndef NULL_PTR +#define NULL_PTR NULL +#endif +