/*
* 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
* 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
*
*/
#include <stdio.h>
#include <link.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <ber_der.h>
#include <kmfapiP.h>
#include <libgen.h>
#include <cryptoutil.h>
{
return (KMF_ERR_BAD_PARAMETER);
return (ret);
}
return (KMF_ERR_MEMORY);
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
goto cleanup;
goto cleanup;
goto cleanup;
}
sizeof (KMF_X509EXT_TAGandVALUE));
goto cleanup;
}
return (ret);
}
/*
* Given a block of DER encoded X.509 certificate data and
* an OID for the desired extension, this routine will
* parse the cert data and return the data associated with
* the extension if it is found.
*
* RETURNS:
* KMF_OK - if extension found and copied OK.
* KMF_ERR_EXTENSION_NOT_FOUND - extension not found.
* parsing and memory allocation errors are also possible.
*/
{
int i, found = 0;
return (KMF_ERR_BAD_PARAMETER);
return (ret);
goto end;
}
for (i = 0; !found &&
i++) {
found++;
}
}
end:
if (!found)
}
return (ret);
}
/*
* Given a block of DER encoded X.509 certificate data and
* return the OIDs for critical, non-critical or all extensions.
*
* RETURNS:
* KMF_OK - if extension found and copied OK.
* parsing and memory allocation errors are also possible.
*
* OIDlist - array of KMF_OID records, allocated
* by this function.
* NumOIDs - number of critical extensions found.
*/
{
int i;
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_BAD_PARAMETER);
*nextns = 0;
return (ret);
return (KMF_ERR_EXTENSION_NOT_FOUND);
i++) {
continue;
continue;
(*nextns)++;
(*nextns));
goto end;
}
goto end;
}
end:
}
*nextns = 0;
}
/*
* If the flag is not all, then it is possible that we did not find
* any critical or non_critical extensions. When that happened,
* return KMF_ERR_EXTENSION_NOT_FOUND.
*/
return (ret);
}
/*
* If the given certificate data (X.509 DER encoded data)
* contains the Key Usage extension, parse that
* data and return it in the KMF_X509EXT_BASICCONSTRAINTS
* record.
*
* RETURNS:
* KMF_OK - success
* KMF_ERR_BAD_PARAMETER - input data was bad.
* KMF_ERR_EXTENSION_NOT_FOUND - extension not found.
*/
{
return (KMF_ERR_BAD_PARAMETER);
/*
* Check standard KeyUsage bits
*/
goto end;
}
} else {
}
end:
return (ret);
}
{
int i;
return (0);
return (1);
return (0);
}
{
/*
* Decode the ASN.1 data for the extension.
*/
goto end;
}
/*
* certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
*/
goto end;
}
/*
* Count the number of EKU OIDs and store in
* the array.
*/
/* Skip over the CONSTRUCTED SET tag */
goto end;
}
goto end;
}
}
end:
}
}
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
goto end;
}
end:
return (ret);
}
/*
* If the given certificate data (X.509 DER encoded data)
* contains the Basic Constraints extension, parse that
* data and return it in the KMF_X509EXT_BASICCONSTRAINTS
* record.
*
* RETURNS:
* KMF_OK - success
* KMF_ERR_BAD_PARAMETER - input data was bad.
* KMF_ERR_EXTENSION_NOT_FOUND - extension not found.
*/
{
int tag;
return (KMF_ERR_BAD_PARAMETER);
goto end;
}
goto end;
}
goto end;
}
if (tag == BER_INTEGER) {
goto end;
}
}
end:
return (ret);
}
static KMF_X509EXT_POLICYQUALIFIERINFO *
{
int tag;
/*
* Policy Qualifiers may be a list of sequences.
*
* PolicyInformation ::= SEQUENCE {
* policyIdentifier CertPolicyId,
* policyQualifiers SEQUENCE SIZE (1..MAX) OF
* PolicyQualifierInfo OPTIONAL
* }
*
* PolicyQualifierInfo ::= SEQUENCE {
* policyQualifierId PolicyQualifierId,
* qualifier ANY DEFINED BY policyQualifierId
* }
*/
/*
* We already got the CertPolicyId, we just need to
* find all of the policyQualifiers in the set.
*
* Mark the first element of the SEQUENCE and reset the end ptr
*/
goto end;
}
/* We found a sequence, loop until done */
/* Skip over the CONSTRUCTED SET tag */
goto end;
}
/*
* Allocate memory for the Policy Qualifier Info
*/
goto end;
}
sizeof (KMF_X509EXT_POLICYQUALIFIERINFO));
/*
* Read the PolicyQualifier OID
*/
goto end;
}
/*
* The OID of the policyQualifierId determines what
* sort of data comes next.
*/
(KMF_OID *)&KMFOID_PKIX_PQ_CPSuri)) {
/*
* CPS uri must be an IA5STRING
*/
size == 0) {
goto end;
}
goto end;
}
goto end;
}
(KMF_OID *)&KMFOID_PKIX_PQ_Unotice)) {
tag != BER_CONSTRUCTED_SEQUENCE) {
goto end;
}
/*
* For now, just copy the while UserNotice ASN.1
* blob into the pqinfo data record.
* TBD - parse it into individual fields.
*/
goto end;
}
goto end;
}
} else {
goto end;
}
}
end:
}
}
return (pqinfo);
}
/*
* If the given certificate data (X.509 DER encoded data)
* contains the Certificate Policies extension, parse that
* data and return it in the KMF_X509EXT_CERT_POLICIES
* record.
*
* RETURNS:
* KMF_OK - success
* KMF_ERR_BAD_PARAMETER - input data was bad.
* KMF_ERR_EXTENSION_NOT_FOUND - extension not found.
* parsing and memory allocation errors are also possible.
*/
{
int tag;
return (KMF_ERR_BAD_PARAMETER);
goto end;
}
/*
* Decode the ASN.1 data for the extension.
*/
goto end;
}
/*
* certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
*/
goto end;
}
/*
* Collect all of the PolicyInformation SEQUENCES
*
* PolicyInformation ::= SEQUENCE {
* policyIdentifier CertPolicyId,
* policyQualifiers SEQUENCE SIZE (1..MAX) OF
* PolicyQualifierInfo OPTIONAL
* }
*
* Loop over the SEQUENCES of PolicyInfo
*/
/* Skip over the CONSTRUCTED SET tag */
goto end;
}
goto end;
}
sizeof (KMF_X509EXT_POLICYINFO));
/*
* Decode the PolicyInformation SEQUENCE
*/
goto end;
}
/*
* Gather all of the associated PolicyQualifierInfo recs
*/
int cnt =
cnt++;
cnt * sizeof (KMF_X509EXT_POLICYQUALIFIERINFO));
goto end;
}
*pqinfo;
}
sizeof (KMF_X509EXT_POLICYINFO));
goto end;
}
}
end:
return (ret);
}
/*
* If the given certificate data (X.509 DER encoded data)
* contains the Authority Information Access extension, parse that
* data and return it in the KMF_X509EXT_AUTHINFOACCESS
* record.
*
* RETURNS:
* KMF_OK - success
* KMF_ERR_BAD_PARAMETER - input data was bad.
* KMF_ERR_EXTENSION_NOT_FOUND - extension not found.
*/
{
int tag;
return (KMF_ERR_BAD_PARAMETER);
}
goto end;
}
/*
* Decode the ASN.1 data for the extension.
*/
goto end;
}
/*
* AuthorityInfoAccessSyntax ::=
* SEQUENCE SIZE (1..MAX) OF AccessDescription
*/
goto end;
}
/*
* AccessDescription ::= SEQUENCE {
* accessMethod OBJECT IDENTIFIER,
* accessLocation GeneralName }
*/
/* Skip over the CONSTRUCTED SET tag */
goto end;
}
if (access_info == NULL) {
goto end;
}
(void) memset((void *)access_info, 0,
sizeof (KMF_X509EXT_ACCESSDESC));
/*
* Read the AccessMethod OID
*/
goto end;
}
/*
* The OID of the AccessMethod determines what
* sort of data comes next.
*/
(KMF_OID *)&KMFOID_PkixAdOcsp)) {
KMFBER_DEFAULT || size == 0) {
goto end;
}
/*
* OCSP uri must be an IA5STRING or a GENNAME_URI
* with an implicit tag.
*/
if (tag != BER_IA5STRING &&
goto end;
}
goto end;
}
goto end;
}
(KMF_OID *)&KMFOID_PkixAdCaIssuers)) {
/* will be supported later with PKIX */
access_info = NULL;
continue;
} else {
goto end;
}
sizeof (KMF_X509EXT_ACCESSDESC));
goto end;
}
access_info = NULL;
}
end:
if (access_info != NULL)
return (ret);
}
/*
* This function parses the name portion of a der-encoded distribution point
* returns it in the KMF_CRL_DIST_POINT record.
*
* The "DistributionPointName" syntax is
*
* DistributionPointName ::= CHOICE {
* fullName [0] GeneralNames,
* nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
*
* GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GerneralName
*
* Note: for phase 1, we support fullName only.
*/
static KMF_RETURN
{
int tag;
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_BAD_CERT_FORMAT);
goto out;
}
/* Skip over the explicit tag and size */
while (tag != KMFBER_DEFAULT &&
tag != KMFBER_END_OF_SEQORSET) {
KMFBER_DEFAULT || size == 0) {
goto out;
}
/* For phase 1, we are interested in a URI name only */
continue;
}
goto out;
}
/* Skip type and len, then read url and save it. */
goto out;
}
(ber_slen_t)size) {
goto out;
}
goto out;
}
size;
(unsigned char *)url;
/* next */
}
} else if (tag == 0xA1) {
/* "nameRelativeToCRLIssuer" is not supported at phase 1. */
goto out;
}
out:
}
}
return (ret);
}
/*
* This function retrieves the CRL Distribution Points extension data from
* a DER encoded certificate if it contains this extension, parses the
* extension data, and returns it in the KMF_X509EXT_CRLDISTPOINTS record.
*/
{
int tag;
int i;
return (KMF_ERR_BAD_PARAMETER);
}
/* Get the ASN.1 data for this extension. */
return (ret);
}
/*
* Decode the CRLDistributionPoints ASN.1 data. The Syntax for
* CRLDistributionPoints is
*
* CRLDistributionPoints ::=
* SEQUENCE SIZE (1..MAX) OF DistributionPoint
*
* DistributionPoint ::= SEQUENCE {
* distributionPoint [0] DistributionPointName OPTIONAL,
* reasons [1] ReasonFlags OPTIONAL,
* cRLIssuer [2] GeneralNames OPTIONAL }
*/
goto out;
}
goto out;
}
/* Skip over the CONSTRUCTED SET tag */
goto out;
}
goto out;
goto out;
}
char *name_der;
goto out;
}
(ber_slen_t)(name_size)) {
goto out;
}
goto out;
}
/* next field */
}
char *bit_string;
int len;
goto out;
}
NULL) {
goto out;
}
/* next field */
}
int issuer_size;
/* For cRLIssuer, read the data only at phase 1 */
if (issuer_der == NULL) {
goto out;
}
(ber_slen_t)(issuer_size)) {
goto out;
}
has_issuer = B_TRUE;
}
/* A distribution point cannot have a "reasons" field only. */
goto out;
}
/*
* Although it is legal that a distribution point contains
* a cRLIssuer field only, with or without "reasons", we will
* skip it if the name field is not presented for phase 1.
*/
} else {
goto out;
}
/* free the dp itself since we just used its contents */
}
}
}
out:
}
}
return (ret);
}
static KMF_RETURN
{
KMF_PRINTABLE_ITEM, char *);
return (ret);
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.
*/
return (KMF_ERR_PLUGIN_NOTFOUND);
}
"OpenSSL_CertGetPrintable");
if (getPrintableFn == NULL) {
return (KMF_ERR_FUNCTION_NOT_FOUND);
}
}
char **result)
{
char *tmpstr;
return (ret);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
tmpstr);
} else {
}
return (ret);
}
char **result)
{
char *tmpstr;
return (ret);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
tmpstr);
} else {
}
return (ret);
}
char **result)
{
char *tmpstr;
return (ret);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
tmpstr);
} else {
}
return (ret);
}
char **result)
{
char *tmpstr;
return (ret);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
tmpstr);
} else {
}
return (ret);
}
char **result)
{
char *tmpstr;
return (ret);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
tmpstr);
} else {
}
return (ret);
}
char **result)
{
char *tmpstr;
return (ret);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
tmpstr);
} else {
}
return (ret);
}
char **result)
{
char *tmpstr;
return (ret);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
tmpstr);
} else {
}
return (ret);
}
char **result)
{
char *tmpstr;
return (ret);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
tmpstr);
} else {
}
return (ret);
}
char **result)
{
char *tmpstr;
return (ret);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
tmpstr);
} else {
}
return (ret);
}
char **result)
{
char *tmpstr;
return (ret);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
} else {
}
return (ret);
}
/*
* Given a certificate (DER Encoded data) and a KMF
* extension identifier constant (e.g. KMF_X509_EXT_*),
* return a human readable interpretation of the
* extension data.
*
* The string will be a maximum of KMF_CERT_PRINTABLE_LEN
* bytes long. The string is allocated locally and
* must be freed by the caller.
*/
{
char *tmpstr;
return (ret);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
} else {
}
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
return (ret);
return (ret);
}
{
int i;
return (KMF_ERR_BAD_PARAMETER);
kmf_free_data(&ID);
return (ret);
}
}
kmf_free_data(&ID);
return (ret);
}
/*
* This function gets the time_t values of the notbefore and notafter dates
* from a der-encoded certificate.
*/
{
unsigned char *not_before_str;
unsigned char *not_after_str;
return (KMF_ERR_BAD_PARAMETER);
return (rv);
/* Get notBefore */
goto out;
}
errno = 0;
goto out;
}
/* Get notAfter */
goto out;
}
errno = 0;
goto out;
}
*not_after = t_notafter;
out:
}
return (rv);
}
{
return (ret);
return (KMF_ERR_BAD_PARAMETER);
}
/* The keystore must extract the pubkey data */
} else {
return (KMF_ERR_PLUGIN_NOTFOUND);
}
}
return (ret);
}
{
}
} else {
return (KMF_ERR_BAD_PARAMETER);
}
return (rv);
}
{
int bitlen, i;
return (KMF_ERR_BAD_PARAMETER);
return (ret);
/* empty body */
;
bitlen = 16 - i;
return (KMF_ERR_MEMORY);
goto out;
}
goto out;
}
}
out:
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
return (ret);
}
{
}
} else {
return (KMF_ERR_BAD_PARAMETER);
}
return (rv);
}
{
return (KMF_ERR_BAD_PARAMETER);
(void) copy_data(
(void) copy_data(
} else {
return (KMF_ERR_BAD_PARAMETER);
}
return (KMF_OK);
}
{
return (KMF_ERR_BAD_PARAMETER);
/* Set up validity fields */
else
/* Build the format in 2 parts so SCCS doesn't get confused */
"%y%m%d%H" "%M00Z", gmt);
strlen((char *)szNotBefore);
/* Build the format in 2 parts so SCCS doesn't get confused */
"%y%m%d%H" "%M00Z", gmt);
strlen((char *)szNotAfter);
return (KMF_OK);
}
/*
* Utility routine to set Integer values in the Certificate template
* for things like serialNumber and Version. The data structure
* expects pointers, not literal values, so we must allocate
* and copy here. Don't use memory from the stack since this data
* is freed later and that would be bad.
*/
{
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
return (KMF_OK);
}
static KMF_RETURN
{
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
return (KMF_OK);
}
{
return (KMF_ERR_BAD_PARAMETER);
}
{
return (KMF_ERR_BAD_PARAMETER);
/*
* From RFC 3280:
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
*/
return (KMF_ERR_BAD_PARAMETER);
sizeof (uint32_t)));
}
int critical,
char *namedata)
{
return (KMF_ERR_BAD_PARAMETER);
}
int critical,
char *namedata)
{
return (KMF_ERR_BAD_PARAMETER);
}
int critical)
{
return (KMF_ERR_BAD_PARAMETER);
goto out;
/*
* If the EKU is already in the cert, then just return OK.
*/
goto out;
}
}
}
return (KMF_ERR_MEMORY);
goto out;
}
/* Write the old extension data first */
goto out;
}
}
/* Append this EKU OID and close the sequence */
goto out;
}
goto out;
}
/*
* If we are just adding to an existing list of EKU OIDs,
* just replace the BER data associated with the found extension.
*/
} else {
goto out;
}
out:
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
return (ret);
return (KMF_ERR_MEMORY);
goto out;
}
goto out;
}
if (constraint->pathLenConstraintPresent) {
/* Write the pathLenConstraint value */
goto out;
}
}
goto out;
}
goto out;
}
}
out:
return (ret);
}
/*
* Phase 1 APIs still needed to maintain compat with elfsign.
*/
char **result)
{
}
char **result)
{
}
{
}