static CK_RV add_certificate(const char *cert_file, const char *pin, char *id, char *label) { hx509_certs certs; hx509_lock lock = NULL; int ret, flags = 0; struct foo foo; foo.id = id; foo.label = label; if (pin == NULL) flags |= HX509_CERTS_UNPROTECT_ALL; if (pin) { char *str; ret = asprintf(&str, "PASS:%s", pin); if (ret == -1 || !str) { st_logf("failed to allocate memory\n"); return CKR_GENERAL_ERROR; } hx509_lock_init(context, &lock); hx509_lock_command_string(lock, str); memset(str, 0, strlen(str)); free(str); } ret = hx509_certs_init(context, cert_file, flags, lock, &certs); if (ret) { st_logf("failed to open file %s\n", cert_file); return CKR_GENERAL_ERROR; } ret = hx509_certs_iter_f(context, certs, add_cert, &foo); hx509_certs_free(&certs); if (ret) { st_logf("failed adding certs from file %s\n", cert_file); return CKR_GENERAL_ERROR; } return CKR_OK; }
static int file_store(hx509_context context, hx509_certs certs, void *data, int flags, hx509_lock lock) { struct ks_file *ksf = data; struct store_ctx sc; int ret; sc.f = fopen(ksf->fn, "w"); if (sc.f == NULL) { hx509_set_error_string(context, 0, ENOENT, "Failed to open file %s for writing"); return ENOENT; } rk_cloexec_file(sc.f); sc.format = ksf->format; ret = hx509_certs_iter_f(context, ksf->certs, store_func, &sc); fclose(sc.f); return ret; }
int hx509_cms_create_signed(hx509_context context, int flags, const heim_oid *eContentType, const void *data, size_t length, const AlgorithmIdentifier *digest_alg, hx509_certs certs, hx509_peer_info peer, hx509_certs anchors, hx509_certs pool, heim_octet_string *signed_data) { unsigned int i, j; hx509_name name; int ret; size_t size; struct sigctx sigctx; memset(&sigctx, 0, sizeof(sigctx)); memset(&name, 0, sizeof(name)); if (eContentType == NULL) eContentType = &asn1_oid_id_pkcs7_data; sigctx.digest_alg = digest_alg; sigctx.content.data = rk_UNCONST(data); sigctx.content.length = length; sigctx.eContentType = eContentType; sigctx.peer = peer; /** * Use HX509_CMS_SIGNATURE_ID_NAME to preferred use of issuer name * and serial number if possible. Otherwise subject key identifier * will preferred. */ if (flags & HX509_CMS_SIGNATURE_ID_NAME) sigctx.cmsidflag = CMS_ID_NAME; else sigctx.cmsidflag = CMS_ID_SKI; /** * Use HX509_CMS_SIGNATURE_LEAF_ONLY to only request leaf * certificates to be added to the SignedData. */ sigctx.leafonly = (flags & HX509_CMS_SIGNATURE_LEAF_ONLY) ? 1 : 0; /** * Use HX509_CMS_NO_CERTS to make the SignedData contain no * certificates, overrides HX509_CMS_SIGNATURE_LEAF_ONLY. */ if ((flags & HX509_CMS_SIGNATURE_NO_CERTS) == 0) { ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs); if (ret) return ret; } sigctx.anchors = anchors; sigctx.pool = pool; sigctx.sd.version = CMSVersion_v3; der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType); /** * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures. */ if ((flags & HX509_CMS_SIGNATURE_DETACHED) == 0) { ALLOC(sigctx.sd.encapContentInfo.eContent, 1); if (sigctx.sd.encapContentInfo.eContent == NULL) { hx509_clear_error_string(context); ret = ENOMEM; goto out; } sigctx.sd.encapContentInfo.eContent->data = malloc(length); if (sigctx.sd.encapContentInfo.eContent->data == NULL) { hx509_clear_error_string(context); ret = ENOMEM; goto out; } memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length); sigctx.sd.encapContentInfo.eContent->length = length; } /** * Use HX509_CMS_SIGNATURE_NO_SIGNER to create no sigInfo (no * signatures). */ if ((flags & HX509_CMS_SIGNATURE_NO_SIGNER) == 0) { ret = hx509_certs_iter_f(context, certs, sig_process, &sigctx); if (ret) goto out; } if (sigctx.sd.signerInfos.len) { /* * For each signerInfo, collect all different digest types. */ for (i = 0; i < sigctx.sd.signerInfos.len; i++) { AlgorithmIdentifier *di = &sigctx.sd.signerInfos.val[i].digestAlgorithm; for (j = 0; j < sigctx.sd.digestAlgorithms.len; j++) if (cmp_AlgorithmIdentifier(di, &sigctx.sd.digestAlgorithms.val[j]) == 0) break; if (j == sigctx.sd.digestAlgorithms.len) { ret = add_DigestAlgorithmIdentifiers(&sigctx.sd.digestAlgorithms, di); if (ret) { hx509_clear_error_string(context); goto out; } } } } /* * Add certs we think are needed, build as part of sig_process */ if (sigctx.certs) { ALLOC(sigctx.sd.certificates, 1); if (sigctx.sd.certificates == NULL) { hx509_clear_error_string(context); ret = ENOMEM; goto out; } ret = hx509_certs_iter_f(context, sigctx.certs, cert_process, &sigctx); if (ret) goto out; } ASN1_MALLOC_ENCODE(SignedData, signed_data->data, signed_data->length, &sigctx.sd, &size, ret); if (ret) { hx509_clear_error_string(context); goto out; } if (signed_data->length != size) _hx509_abort("internal ASN.1 encoder error"); out: hx509_certs_free(&sigctx.certs); free_SignedData(&sigctx.sd); return ret; }
static int p12_store(hx509_context context, hx509_certs certs, void *data, int flags, hx509_lock lock) { struct ks_pkcs12 *p12 = data; PKCS12_PFX pfx; PKCS12_AuthenticatedSafe as; PKCS12_OctetString asdata; size_t size; int ret; memset(&as, 0, sizeof(as)); memset(&pfx, 0, sizeof(pfx)); ret = hx509_certs_iter_f(context, p12->certs, store_func, &as); if (ret) goto out; ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length, &as, &size, ret); free_PKCS12_AuthenticatedSafe(&as); if (ret) return ret; ret = der_parse_hex_heim_integer("03", &pfx.version); if (ret) { free(asdata.data); goto out; } pfx.authSafe.content = calloc(1, sizeof(*pfx.authSafe.content)); ASN1_MALLOC_ENCODE(PKCS12_OctetString, pfx.authSafe.content->data, pfx.authSafe.content->length, &asdata, &size, ret); free(asdata.data); if (ret) goto out; ret = der_copy_oid(&asn1_oid_id_pkcs7_data, &pfx.authSafe.contentType); if (ret) goto out; ASN1_MALLOC_ENCODE(PKCS12_PFX, asdata.data, asdata.length, &pfx, &size, ret); if (ret) goto out; #if 0 const struct _hx509_password *pw; pw = _hx509_lock_get_passwords(lock); if (pw != NULL) { pfx.macData = calloc(1, sizeof(*pfx.macData)); if (pfx.macData == NULL) { ret = ENOMEM; hx509_set_error_string(context, 0, ret, "malloc out of memory"); return ret; } if (pfx.macData == NULL) { free(asdata.data); goto out; } } ret = calculate_hash(&aspath, pw, pfx.macData); #endif rk_dumpdata(p12->fn, asdata.data, asdata.length); free(asdata.data); out: free_PKCS12_AuthenticatedSafe(&as); free_PKCS12_PFX(&pfx); return ret; }
int hx509_ocsp_request(hx509_context context, hx509_certs reqcerts, hx509_certs pool, hx509_cert signer, const AlgorithmIdentifier *digest, heim_octet_string *request, heim_octet_string *nonce) { OCSPRequest req; size_t size; int ret; struct ocsp_add_ctx ctx; Extensions *es; memset(&req, 0, sizeof(req)); if (digest == NULL) digest = _hx509_crypto_default_digest_alg; ctx.req = &req.tbsRequest; ctx.certs = pool; ctx.digest = digest; ctx.parent = NULL; ret = hx509_certs_iter_f(context, reqcerts, add_to_req, &ctx); hx509_cert_free(ctx.parent); if (ret) goto out; if (nonce) { req.tbsRequest.requestExtensions = calloc(1, sizeof(*req.tbsRequest.requestExtensions)); if (req.tbsRequest.requestExtensions == NULL) { ret = ENOMEM; goto out; } es = req.tbsRequest.requestExtensions; es->val = calloc(es->len, sizeof(es->val[0])); if (es->val == NULL) { ret = ENOMEM; goto out; } es->len = 1; ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID); if (ret) { free_OCSPRequest(&req); return ret; } es->val[0].extnValue.data = malloc(10); if (es->val[0].extnValue.data == NULL) { ret = ENOMEM; goto out; } es->val[0].extnValue.length = 10; ret = RAND_bytes(es->val[0].extnValue.data, es->val[0].extnValue.length); if (ret != 1) { ret = HX509_CRYPTO_INTERNAL_ERROR; goto out; } ret = der_copy_octet_string(nonce, &es->val[0].extnValue); if (ret) { ret = ENOMEM; goto out; } } ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length, &req, &size, ret); free_OCSPRequest(&req); if (ret) goto out; if (size != request->length) _hx509_abort("internal ASN.1 encoder error"); return 0; out: free_OCSPRequest(&req); return ret; }
int hx509_crl_sign(hx509_context context, hx509_cert signer, hx509_crl crl, heim_octet_string *os) { const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg; CRLCertificateList c; size_t size; int ret; hx509_private_key signerkey; memset(&c, 0, sizeof(c)); signerkey = _hx509_cert_private_key(signer); if (signerkey == NULL) { ret = HX509_PRIVATE_KEY_MISSING; hx509_set_error_string(context, 0, ret, "Private key missing for CRL signing"); return ret; } c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version)); if (c.tbsCertList.version == NULL) { hx509_set_error_string(context, 0, ENOMEM, "out of memory"); return ENOMEM; } *c.tbsCertList.version = 1; ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature); if (ret) { hx509_clear_error_string(context); goto out; } ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer, &c.tbsCertList.issuer); if (ret) { hx509_clear_error_string(context); goto out; } c.tbsCertList.thisUpdate.element = choice_Time_generalTime; c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600; c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate)); if (c.tbsCertList.nextUpdate == NULL) { hx509_set_error_string(context, 0, ENOMEM, "out of memory"); ret = ENOMEM; goto out; } { time_t next = crl->expire; if (next == 0) next = time(NULL) + 24 * 3600 * 365; c.tbsCertList.nextUpdate->element = choice_Time_generalTime; c.tbsCertList.nextUpdate->u.generalTime = next; } c.tbsCertList.revokedCertificates = calloc(1, sizeof(*c.tbsCertList.revokedCertificates)); if (c.tbsCertList.revokedCertificates == NULL) { hx509_set_error_string(context, 0, ENOMEM, "out of memory"); ret = ENOMEM; goto out; } c.tbsCertList.crlExtensions = NULL; ret = hx509_certs_iter_f(context, crl->revoked, add_revoked, &c.tbsCertList); if (ret) goto out; /* if not revoked certs, remove OPTIONAL entry */ if (c.tbsCertList.revokedCertificates->len == 0) { free(c.tbsCertList.revokedCertificates); c.tbsCertList.revokedCertificates = NULL; } ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length, &c.tbsCertList, &size, ret); if (ret) { hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL"); goto out; } if (size != os->length) _hx509_abort("internal ASN.1 encoder error"); ret = _hx509_create_signature_bitstring(context, signerkey, sigalg, os, &c.signatureAlgorithm, &c.signatureValue); free(os->data); if (ret) { hx509_set_error_string(context, 0, ret, "Failed to sign CRL"); goto out; } ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length, &c, &size, ret); if (ret) { hx509_set_error_string(context, 0, ret, "failed to encode CRL"); goto out; } if (size != os->length) _hx509_abort("internal ASN.1 encoder error"); free_CRLCertificateList(&c); return 0; out: free_CRLCertificateList(&c); return ret; }
int hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out) { struct revoke_ocsp ocsp; int ret; size_t i; if (out == NULL) out = stdout; memset(&ocsp, 0, sizeof(ocsp)); ocsp.path = strdup(path); if (ocsp.path == NULL) return ENOMEM; ret = load_ocsp(context, &ocsp); if (ret) { free_ocsp(&ocsp); return ret; } fprintf(out, "signer: "); switch(ocsp.ocsp.tbsResponseData.responderID.element) { case choice_OCSPResponderID_byName: { hx509_name n; char *s; _hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n); hx509_name_to_string(n, &s); hx509_name_free(&n); fprintf(out, " byName: %s\n", s); free(s); break; } case choice_OCSPResponderID_byKey: { char *s; hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data, ocsp.ocsp.tbsResponseData.responderID.u.byKey.length, &s); fprintf(out, " byKey: %s\n", s); free(s); break; } default: _hx509_abort("choice_OCSPResponderID unknown"); break; } fprintf(out, "producedAt: %s\n", printable_time(ocsp.ocsp.tbsResponseData.producedAt)); fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len); for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) { const char *status; switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) { case choice_OCSPCertStatus_good: status = "good"; break; case choice_OCSPCertStatus_revoked: status = "revoked"; break; case choice_OCSPCertStatus_unknown: status = "unknown"; break; default: status = "element unknown"; } fprintf(out, "\t%zu. status: %s\n", i, status); fprintf(out, "\tthisUpdate: %s\n", printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate)); if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate) fprintf(out, "\tproducedAt: %s\n", printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate)); } fprintf(out, "appended certs:\n"); if (ocsp.certs) ret = hx509_certs_iter_f(context, ocsp.certs, hx509_ci_print_names, out); free_ocsp(&ocsp); return ret; }