/** * Adds all subjects in a PKCS12 files and notifies the frontend of them. */ static TokenError _backend_addFile(Backend *backend, const char *data, size_t length, void *tag) { SharedPKCS12 *p12 = pkcs12_parse(data, length); if (!p12) return TokenError_BadFile; STACK_OF(X509) *certList = pkcs12_listCerts(p12->data); if (!certList) return TokenError_Unknown; int certCount = sk_X509_num(certList); for (int i = 0; i < certCount; i++) { X509 *x = sk_X509_value(certList, i); if (!certutil_hasKeyUsage(x, backend->notifier->keyUsage)) goto dontAddCert; X509_NAME *id = X509_get_subject_name(x); if (!certutil_matchSubjectFilter(backend->notifier->subjectFilter, id)) goto dontAddCert; PKCS12Token *token = createToken(backend, p12, id, tag); if (token) { backend->notifier->notifyFunction((Token*)token, TokenChange_Added); continue; } dontAddCert: X509_free(x); } pkcs12_release(p12); return TokenError_Success; }
/** * Returns a list of DER-BASE64 encoded certificates, from the subject * to the root CA. */ static TokenError _backend_getBase64Chain(const PKCS12Token *token, char ***certs, size_t *count) { STACK_OF(X509) *certList = pkcs12_listCerts(token->sharedP12->data); if (!certList) return TokenError_Unknown; X509 *cert = certutil_findCert(certList, token->subjectName, token->base.backend->notifier->keyUsage, false); if (!cert) { sk_X509_pop_free(certList, X509_free); return TokenError_Unknown; } *count = 0; *certs = NULL; if (!certutil_addToList(certs, count, cert)) goto error; X509_NAME *issuer = X509_get_issuer_name(cert); while (issuer != NULL) { cert = certutil_findCert(certList, issuer, KeyUsage_Issuing, false); if (!cert) break; issuer = X509_get_issuer_name(cert); if (!certutil_addToList(certs, count, cert)) goto error; } sk_X509_pop_free(certList, X509_free); return TokenError_Success; error: certutil_freeList(certs, count); return TokenError_Unknown; }
static TokenError _backend_sign(PKCS12Token *token, const char *message, size_t messagelen, char **signature, size_t *siglen) { if (!message || !signature || !siglen) { assert(false); return TokenError_Unknown; } if (messagelen >= UINT_MAX) return TokenError_MessageTooLong; // Find the certificate for the token STACK_OF(X509) *certList = pkcs12_listCerts(token->sharedP12->data); if (!certList) return TokenError_Unknown; X509 *cert = certutil_findCert(certList, token->subjectName, token->base.backend->notifier->keyUsage, false); if (!cert) { sk_X509_pop_free(certList, X509_free); return TokenError_Unknown; } // Get the corresponding private key EVP_PKEY *key = getPrivateKey(token->sharedP12->data, cert, token->base.password); sk_X509_pop_free(certList, X509_free); if (!key) return TokenError_BadPassword; // Sign with the default crypto with SHA1 unsigned int sig_len = EVP_PKEY_size(key); *siglen = sig_len; *signature = malloc(sig_len); EVP_MD_CTX sig_ctx; EVP_MD_CTX_init(&sig_ctx); bool success = (EVP_SignInit(&sig_ctx, EVP_sha1()) && EVP_SignUpdate(&sig_ctx, message, messagelen) && EVP_SignFinal(&sig_ctx, (unsigned char*)*signature, &sig_len, key)); EVP_MD_CTX_cleanup(&sig_ctx); EVP_PKEY_free(key); *siglen = sig_len; if (success) { return TokenError_Success; } else { certutil_updateErrorString(); free(*signature); return TokenError_SignatureFailure; } }