csrcrlop.c revision 30a5e8fa1253cb33980ee4514743cf683f584b4e
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <link.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <ber_der.h>
#include <kmfapiP.h>
#include <pem_encode.h>
#include <libgen.h>
#include <cryptoutil.h>
static KMF_RETURN
setup_crl_call(KMF_HANDLE_T, int, KMF_ATTRIBUTE *, KMF_PLUGIN **);
/*
*
* Name: kmf_set_csr_pubkey
*
* Description:
* This function converts the specified plugin public key to SPKI form,
* and save it in the KMF_CSR_DATA internal structure
*
* Parameters:
* KMFkey(input) - pointer to the KMF_KEY_HANDLE structure containing the
* public key generated by the plug-in CreateKeypair
* Csr(input/output) - pointer to a KMF_CSR_DATA structure containing
* SPKI
*
* Returns:
* A KMF_RETURN value indicating success or specifying a particular
* error condition.
* The value KMF_OK indicates success. All other values represent
* an error condition.
*
*/
KMF_RETURN
kmf_set_csr_pubkey(KMF_HANDLE_T handle,
KMF_KEY_HANDLE *KMFKey,
KMF_CSR_DATA *Csr)
{
KMF_RETURN ret;
KMF_X509_SPKI *spki_ptr;
KMF_PLUGIN *plugin;
KMF_DATA KeyData = {NULL, 0};
CLEAR_ERROR(handle, ret);
if (ret != KMF_OK)
return (ret);
if (KMFKey == NULL || Csr == NULL) {
return (KMF_ERR_BAD_PARAMETER);
}
/* The keystore must extract the pubkey data */
plugin = FindPlugin(handle, KMFKey->kstype);
if (plugin != NULL && plugin->funclist->EncodePubkeyData != NULL) {
ret = plugin->funclist->EncodePubkeyData(handle,
KMFKey, &KeyData);
} else {
return (KMF_ERR_PLUGIN_NOTFOUND);
}
spki_ptr = &Csr->csr.subjectPublicKeyInfo;
ret = DerDecodeSPKI(&KeyData, spki_ptr);
kmf_free_data(&KeyData);
return (ret);
}
KMF_RETURN
kmf_set_csr_version(KMF_CSR_DATA *CsrData, uint32_t version)
{
if (CsrData == NULL)
return (KMF_ERR_BAD_PARAMETER);
/*
* From RFC 3280:
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
*/
if (version != 0 && version != 1 && version != 2)
return (KMF_ERR_BAD_PARAMETER);
return (set_integer(&CsrData->csr.version, (void *)&version,
sizeof (uint32_t)));
}
KMF_RETURN
kmf_set_csr_subject(KMF_CSR_DATA *CsrData,
KMF_X509_NAME *subject_name_ptr)
{
KMF_RETURN rv = KMF_OK;
KMF_X509_NAME *temp_name_ptr = NULL;
if (CsrData != NULL && subject_name_ptr != NULL) {
rv = CopyRDN(subject_name_ptr, &temp_name_ptr);
if (rv == KMF_OK) {
CsrData->csr.subject = *temp_name_ptr;
}
} else {
return (KMF_ERR_BAD_PARAMETER);
}
return (rv);
}
KMF_RETURN
kmf_create_csr_file(KMF_DATA *csrdata, KMF_ENCODE_FORMAT format,
char *csrfile)
{
KMF_RETURN rv = KMF_OK;
int fd = -1;
KMF_DATA pemdata = {NULL, 0};
if (csrdata == NULL || csrfile == NULL)
return (KMF_ERR_BAD_PARAMETER);
if (format != KMF_FORMAT_PEM && format != KMF_FORMAT_ASN1)
return (KMF_ERR_BAD_PARAMETER);
if (format == KMF_FORMAT_PEM) {
int len;
rv = kmf_der_to_pem(KMF_CSR,
csrdata->Data, csrdata->Length,
&pemdata.Data, &len);
if (rv != KMF_OK)
goto cleanup;
pemdata.Length = (size_t)len;
}
if ((fd = open(csrfile, O_CREAT |O_RDWR, 0644)) == -1) {
rv = KMF_ERR_OPEN_FILE;
goto cleanup;
}
if (format == KMF_FORMAT_PEM) {
if (write(fd, pemdata.Data, pemdata.Length) !=
pemdata.Length) {
rv = KMF_ERR_WRITE_FILE;
}
} else {
if (write(fd, csrdata->Data, csrdata->Length) !=
csrdata->Length) {
rv = KMF_ERR_WRITE_FILE;
}
}
cleanup:
if (fd != -1)
(void) close(fd);
kmf_free_data(&pemdata);
return (rv);
}
KMF_RETURN
kmf_set_csr_extn(KMF_CSR_DATA *Csr, KMF_X509_EXTENSION *extn)
{
KMF_RETURN ret = KMF_OK;
KMF_X509_EXTENSIONS *exts;
if (Csr == NULL || extn == NULL)
return (KMF_ERR_BAD_PARAMETER);
exts = &Csr->csr.extensions;
ret = add_an_extension(exts, extn);
return (ret);
}
KMF_RETURN
kmf_set_csr_sig_alg(KMF_CSR_DATA *CsrData,
KMF_ALGORITHM_INDEX sigAlg)
{
KMF_OID *alg;
if (CsrData == NULL)
return (KMF_ERR_BAD_PARAMETER);
alg = x509_algid_to_algoid(sigAlg);
if (alg != NULL) {
(void) copy_data((KMF_DATA *)
&CsrData->signature.algorithmIdentifier.algorithm,
(KMF_DATA *)alg);
(void) copy_data(
&CsrData->signature.algorithmIdentifier.parameters,
&CsrData->csr.subjectPublicKeyInfo.algorithm.parameters);
} else {
return (KMF_ERR_BAD_PARAMETER);
}
return (KMF_OK);
}
KMF_RETURN
kmf_set_csr_subject_altname(KMF_CSR_DATA *Csr,
char *altname, int critical,
KMF_GENERALNAMECHOICES alttype)
{
KMF_RETURN ret = KMF_OK;
if (Csr == NULL || altname == NULL)
return (KMF_ERR_BAD_PARAMETER);
ret = kmf_set_altname(&Csr->csr.extensions,
(KMF_OID *)&KMFOID_SubjectAltName, critical, alttype,
altname);
return (ret);
}
KMF_RETURN
kmf_set_csr_ku(KMF_CSR_DATA *CSRData,
int critical, uint16_t kubits)
{
KMF_RETURN ret = KMF_OK;
if (CSRData == NULL)
return (KMF_ERR_BAD_PARAMETER);
ret = set_key_usage_extension(
&CSRData->csr.extensions, critical, kubits);
return (ret);
}
static KMF_RETURN
SignCsr(KMF_HANDLE_T handle,
const KMF_DATA *SubjectCsr,
KMF_KEY_HANDLE *Signkey,
KMF_X509_ALGORITHM_IDENTIFIER *algo,
KMF_DATA *SignedCsr)
{
KMF_CSR_DATA subj_csr;
KMF_TBS_CSR *tbs_csr = NULL;
KMF_DATA signed_data = {0, NULL};
KMF_RETURN ret = KMF_OK;
if (!SignedCsr)
return (KMF_ERR_BAD_PARAMETER);
SignedCsr->Length = 0;
SignedCsr->Data = NULL;
if (!SubjectCsr)
return (KMF_ERR_BAD_PARAMETER);
if (!SubjectCsr->Data || !SubjectCsr->Length)
return (KMF_ERR_BAD_PARAMETER);
(void) memset(&subj_csr, 0, sizeof (subj_csr));
/* Estimate the signed data length generously */
signed_data.Length = SubjectCsr->Length*2;
signed_data.Data = calloc(1, signed_data.Length);
if (!signed_data.Data) {
ret = KMF_ERR_MEMORY;
goto cleanup;
}
/* Sign the data */
ret = KMF_SignDataWithKey(handle, Signkey, &algo->algorithm,
(KMF_DATA *)SubjectCsr, &signed_data);
if (KMF_OK != ret)
goto cleanup;
/*
* If we got here OK, decode into a structure and then re-encode
* the complete CSR.
*/
ret = DerDecodeTbsCsr(SubjectCsr, &tbs_csr);
if (ret)
goto cleanup;
(void) memcpy(&subj_csr.csr, tbs_csr, sizeof (KMF_TBS_CSR));
ret = copy_algoid(&subj_csr.signature.algorithmIdentifier, algo);
if (ret)
goto cleanup;
subj_csr.signature.encrypted = signed_data;
/* Now, re-encode the CSR with the new signature */
ret = DerEncodeSignedCsr(&subj_csr, SignedCsr);
if (ret != KMF_OK) {
kmf_free_data(SignedCsr);
goto cleanup;
}
/* Cleanup & return */
cleanup:
free(tbs_csr);
kmf_free_tbs_csr(&subj_csr.csr);
kmf_free_algoid(&subj_csr.signature.algorithmIdentifier);
kmf_free_data(&signed_data);
return (ret);
}
/*
*
* Name: kmf_sign_csr
*
* Description:
* This function signs a CSR and returns the result as a
* signed, encoded CSR in SignedCsr
*
* Parameters:
* tbsCsr(input) - pointer to a KMF_DATA structure containing a
* DER encoded TBS CSR data
* Signkey(input) - pointer to the KMF_KEY_HANDLE structure containing
* the private key generated by the plug-in CreateKeypair
* algo(input) - contains algorithm info needed for signing
* SignedCsr(output) - pointer to the KMF_DATA structure containing
* the signed CSR
*
* Returns:
* A KMF_RETURN value indicating success or specifying a particular
* error condition.
* The value KMF_OK indicates success. All other values represent
* an error condition.
*
*/
KMF_RETURN
kmf_sign_csr(KMF_HANDLE_T handle,
const KMF_CSR_DATA *tbsCsr,
KMF_KEY_HANDLE *Signkey,
KMF_DATA *SignedCsr)
{
KMF_RETURN err;
KMF_DATA csrdata = { NULL, 0 };
CLEAR_ERROR(handle, err);
if (err != KMF_OK)
return (err);
if (tbsCsr == NULL || Signkey == NULL || SignedCsr == NULL)
return (KMF_ERR_BAD_PARAMETER);
SignedCsr->Data = NULL;
SignedCsr->Length = 0;
err = DerEncodeTbsCsr((KMF_TBS_CSR *)&tbsCsr->csr, &csrdata);
if (err == KMF_OK) {
err = SignCsr(handle, &csrdata, Signkey,
(KMF_X509_ALGORITHM_IDENTIFIER *)
&tbsCsr->signature.algorithmIdentifier,
SignedCsr);
}
if (err != KMF_OK) {
kmf_free_data(SignedCsr);
}
kmf_free_data(&csrdata);
return (err);
}
static KMF_RETURN
setup_crl_call(KMF_HANDLE_T handle, int numattr,
KMF_ATTRIBUTE *attrlist, KMF_PLUGIN **plugin)
{
KMF_RETURN ret;
KMF_KEYSTORE_TYPE kstype;
uint32_t len = sizeof (kstype);
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)}
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
if (handle == NULL || plugin == NULL)
return (KMF_ERR_BAD_PARAMETER);
CLEAR_ERROR(handle, ret);
ret = test_attributes(num_req_attrs, required_attrs,
0, NULL, numattr, attrlist);
if (ret != KMF_OK)
return (ret);
ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
&kstype, &len);
if (ret != KMF_OK)
return (ret);
switch (kstype) {
case KMF_KEYSTORE_NSS:
*plugin = FindPlugin(handle, kstype);
break;
case KMF_KEYSTORE_OPENSSL:
case KMF_KEYSTORE_PK11TOKEN: /* PKCS#11 CRL is file-based */
*plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
break;
default:
return (KMF_ERR_PLUGIN_NOTFOUND);
}
return (KMF_OK);
}
KMF_RETURN
kmf_import_crl(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_RETURN ret;
KMF_PLUGIN *plugin;
ret = setup_crl_call(handle, numattr, attrlist, &plugin);
if (ret != KMF_OK)
return (ret);
if (plugin == NULL)
return (KMF_ERR_PLUGIN_NOTFOUND);
else if (plugin->funclist->ImportCRL != NULL)
return (plugin->funclist->ImportCRL(handle, numattr, attrlist));
return (KMF_ERR_FUNCTION_NOT_FOUND);
}
KMF_RETURN
kmf_delete_crl(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_RETURN ret;
KMF_PLUGIN *plugin;
ret = setup_crl_call(handle, numattr, attrlist, &plugin);
if (ret != KMF_OK)
return (ret);
if (plugin == NULL)
return (KMF_ERR_PLUGIN_NOTFOUND);
else if (plugin->funclist->DeleteCRL != NULL)
return (plugin->funclist->DeleteCRL(handle, numattr, attrlist));
return (KMF_ERR_FUNCTION_NOT_FOUND);
}
KMF_RETURN
kmf_list_crl(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_PLUGIN *plugin;
KMF_RETURN ret;
ret = setup_crl_call(handle, numattr, attrlist, &plugin);
if (ret != KMF_OK)
return (ret);
if (plugin == NULL)
return (KMF_ERR_PLUGIN_NOTFOUND);
else if (plugin->funclist->ListCRL != NULL)
return (plugin->funclist->ListCRL(handle, numattr, attrlist));
return (KMF_ERR_FUNCTION_NOT_FOUND);
}
KMF_RETURN
kmf_find_crl(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_PLUGIN *plugin;
KMF_RETURN ret;
KMF_KEYSTORE_TYPE kstype;
uint32_t len = sizeof (kstype);
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1,
sizeof (KMF_KEYSTORE_TYPE)},
{KMF_CRL_COUNT_ATTR, FALSE,
sizeof (char *), sizeof (char *)}
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
CLEAR_ERROR(handle, ret);
ret = test_attributes(num_req_attrs, required_attrs,
0, NULL, numattr, attrlist);
if (ret != KMF_OK)
return (ret);
ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
&kstype, &len);
if (ret != KMF_OK)
return (ret);
switch (kstype) {
case KMF_KEYSTORE_NSS:
plugin = FindPlugin(handle, kstype);
break;
case KMF_KEYSTORE_OPENSSL:
case KMF_KEYSTORE_PK11TOKEN:
return (KMF_ERR_FUNCTION_NOT_FOUND);
default:
/*
* FindCRL is only implemented for NSS. PKCS#11
* and file-based keystores just store in a file
* and don't need a "Find" function.
*/
return (KMF_ERR_PLUGIN_NOTFOUND);
}
if (plugin == NULL)
return (KMF_ERR_PLUGIN_NOTFOUND);
else if (plugin->funclist->FindCRL != NULL) {
return (plugin->funclist->FindCRL(handle, numattr,
attrlist));
}
return (KMF_ERR_FUNCTION_NOT_FOUND);
}
KMF_RETURN
kmf_find_cert_in_crl(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_RETURN ret;
KMF_PLUGIN *plugin;
ret = setup_crl_call(handle, numattr, attrlist, &plugin);
if (ret != KMF_OK)
return (ret);
if (plugin == NULL)
return (KMF_ERR_PLUGIN_NOTFOUND);
else if (plugin->funclist->FindCertInCRL != NULL)
return (plugin->funclist->FindCertInCRL(handle, numattr,
attrlist));
return (KMF_ERR_FUNCTION_NOT_FOUND);
}
KMF_RETURN
kmf_verify_crl_file(KMF_HANDLE_T handle, char *crlfile, KMF_DATA *tacert)
{
KMF_PLUGIN *plugin;
KMF_RETURN (*verifyCRLFile)(KMF_HANDLE_T, char *, KMF_DATA *);
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
if (plugin == NULL || plugin->dldesc == NULL) {
return (KMF_ERR_PLUGIN_NOTFOUND);
}
verifyCRLFile = (KMF_RETURN(*)())dlsym(plugin->dldesc,
"OpenSSL_VerifyCRLFile");
if (verifyCRLFile == NULL) {
return (KMF_ERR_FUNCTION_NOT_FOUND);
}
return (verifyCRLFile(handle, crlfile, tacert));
}
KMF_RETURN
kmf_check_crl_date(KMF_HANDLE_T handle, char *crlname)
{
KMF_PLUGIN *plugin;
KMF_RETURN (*checkCRLDate)(void *, char *);
KMF_RETURN ret = KMF_OK;
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
CLEAR_ERROR(handle, ret);
if (ret != KMF_OK)
return (ret);
plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
if (plugin == NULL || plugin->dldesc == NULL) {
return (KMF_ERR_PLUGIN_NOTFOUND);
}
checkCRLDate = (KMF_RETURN(*)())dlsym(plugin->dldesc,
"OpenSSL_CheckCRLDate");
if (checkCRLDate == NULL) {
return (KMF_ERR_FUNCTION_NOT_FOUND);
}
return (checkCRLDate(handle, crlname));
}
KMF_RETURN
kmf_is_crl_file(KMF_HANDLE_T handle, char *filename, KMF_ENCODE_FORMAT *pformat)
{
KMF_PLUGIN *plugin;
KMF_RETURN (*IsCRLFileFn)(void *, char *, KMF_ENCODE_FORMAT *);
KMF_RETURN ret = KMF_OK;
CLEAR_ERROR(handle, ret);
if (ret != KMF_OK)
return (ret);
if (filename == NULL || pformat == NULL) {
return (KMF_ERR_BAD_PARAMETER);
}
/*
* This framework function is actually implemented in the openssl
* plugin library, so we find the function address and call it.
*/
plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
if (plugin == NULL || plugin->dldesc == NULL) {
return (KMF_ERR_PLUGIN_NOTFOUND);
}
IsCRLFileFn = (KMF_RETURN(*)())dlsym(plugin->dldesc,
"OpenSSL_IsCRLFile");
if (IsCRLFileFn == NULL) {
return (KMF_ERR_FUNCTION_NOT_FOUND);
}
return (IsCRLFileFn(handle, filename, pformat));
}
/*
* Phase 1 APIs still needed to maintain compat with elfsign.
*/
KMF_RETURN
KMF_CreateCSRFile(KMF_DATA *csrdata, KMF_ENCODE_FORMAT format,
char *csrfile)
{
return (kmf_create_csr_file(csrdata, format, csrfile));
}
KMF_RETURN
KMF_SetCSRPubKey(KMF_HANDLE_T handle,
KMF_KEY_HANDLE *KMFKey,
KMF_CSR_DATA *Csr)
{
return (kmf_set_csr_pubkey(handle, KMFKey, Csr));
}
KMF_RETURN
KMF_SetCSRVersion(KMF_CSR_DATA *CsrData, uint32_t version)
{
return (kmf_set_csr_version(CsrData, version));
}
KMF_RETURN
KMF_SetCSRSignatureAlgorithm(KMF_CSR_DATA *CsrData,
KMF_ALGORITHM_INDEX sigAlg)
{
return (kmf_set_csr_sig_alg(CsrData, sigAlg));
}
KMF_RETURN
KMF_SignCSR(KMF_HANDLE_T handle,
const KMF_CSR_DATA *tbsCsr,
KMF_KEY_HANDLE *Signkey,
KMF_DATA *SignedCsr)
{
return (kmf_sign_csr(handle, tbsCsr, Signkey, SignedCsr));
}
KMF_RETURN
KMF_SetCSRSubjectName(KMF_CSR_DATA *CsrData,
KMF_X509_NAME *subject_name_ptr)
{
return (kmf_set_csr_subject(CsrData, subject_name_ptr));
}