X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/SecurityTests/clxutils/clAppUtils/CertBuilderApp.cpp diff --git a/SecurityTests/clxutils/clAppUtils/CertBuilderApp.cpp b/SecurityTests/clxutils/clAppUtils/CertBuilderApp.cpp new file mode 100644 index 00000000..c3d33060 --- /dev/null +++ b/SecurityTests/clxutils/clAppUtils/CertBuilderApp.cpp @@ -0,0 +1,376 @@ +/* + * CertBuilderApp.cpp - support for constructing certs, CDSA version + */ + +#include "clutils.h" +#include +#include "CertBuilderApp.h" +#include "timeStr.h" +#include +#include +#include +#include +#include +#include +#include +/* private header */ +#include + +/* + * Build up a CSSM_X509_NAME from an arbitrary list of name/OID pairs. + * We do one a/v pair per RDN. + */ +CSSM_X509_NAME *CB_BuildX509Name( + const CB_NameOid *nameArray, + unsigned numNames) +{ + CSSM_X509_NAME *top = (CSSM_X509_NAME *)appMalloc(sizeof(CSSM_X509_NAME), 0); + if(top == NULL) { + return NULL; + } + top->numberOfRDNs = numNames; + top->RelativeDistinguishedName = + (CSSM_X509_RDN_PTR)appMalloc(sizeof(CSSM_X509_RDN) * numNames, 0); + if(top->RelativeDistinguishedName == NULL) { + return NULL; + } + CSSM_X509_RDN_PTR rdn; + const CB_NameOid *nameOid; + unsigned nameDex; + for(nameDex=0; nameDexRelativeDistinguishedName[nameDex]; + nameOid = &nameArray[nameDex]; + rdn->numberOfPairs = 1; + rdn->AttributeTypeAndValue = (CSSM_X509_TYPE_VALUE_PAIR_PTR) + appMalloc(sizeof(CSSM_X509_TYPE_VALUE_PAIR), 0); + CSSM_X509_TYPE_VALUE_PAIR_PTR atvp = rdn->AttributeTypeAndValue; + if(atvp == NULL) { + return NULL; + } + appCopyCssmData(nameOid->oid, &atvp->type); + atvp->valueType = BER_TAG_PRINTABLE_STRING; + atvp->value.Length = strlen(nameOid->string); + atvp->value.Data = (uint8 *)CSSM_MALLOC(atvp->value.Length); + memmove(atvp->value.Data, nameOid->string, atvp->value.Length); + } + return top; +} + +/* free the CSSM_X509_NAME obtained from CB_BuildX509Name */ +void CB_FreeX509Name( + CSSM_X509_NAME *top) +{ + if(top == NULL) { + return; + } + unsigned nameDex; + CSSM_X509_RDN_PTR rdn; + for(nameDex=0; nameDexnumberOfRDNs; nameDex++) { + rdn = &top->RelativeDistinguishedName[nameDex]; + if(rdn->AttributeTypeAndValue) { + for(unsigned aDex=0; aDexnumberOfPairs; aDex++) { + CSSM_X509_TYPE_VALUE_PAIR_PTR atvp = + &rdn->AttributeTypeAndValue[aDex]; + CSSM_FREE(atvp->type.Data); + CSSM_FREE(atvp->value.Data); + } + CSSM_FREE(rdn->AttributeTypeAndValue); + } + } + CSSM_FREE(top->RelativeDistinguishedName); + CSSM_FREE(top); +} + +/* Obtain a CSSM_X509_TIME representing "now" plus specified seconds, or + * from a preformatted gen time string */ +CSSM_X509_TIME *CB_BuildX509Time( + unsigned secondsFromNow, /* ignored if timeStr non-NULL */ + const char *timeStr) /* optional, from genTimeAtNowPlus */ +{ + CSSM_X509_TIME *xtime = (CSSM_X509_TIME *)appMalloc(sizeof(CSSM_X509_TIME), 0); + if(xtime == NULL) { + return NULL; + } + xtime->timeType = BER_TAG_GENERALIZED_TIME; + char *ts; + if(timeStr == NULL) { + ts = genTimeAtNowPlus(secondsFromNow); + } + else { + ts = (char *)appMalloc(strlen(timeStr) + 1, 0); + strcpy(ts, timeStr); + } + xtime->time.Data = (uint8 *)ts; + xtime->time.Length = strlen(ts); + return xtime; +} + +/* Free CSSM_X509_TIME obtained in CB_BuildX509Time */ +void CB_FreeX509Time( + CSSM_X509_TIME *xtime) +{ + if(xtime == NULL) { + return; + } + freeTimeString((char *)xtime->time.Data); + appFree(xtime, 0); +} + +/* + * Encode an OID as a CSSM_X509_ALGORITHM_IDENTIFIER. + * Returns nonzero on error. + * Returned data is appMallocd's caller must appFree. + */ +int encodeParamOid( + const CSSM_OID *paramOid, + CSSM_DATA *params) +{ + SecAsn1CoderRef coder = NULL; + if(SecAsn1CoderCreate(&coder)) { + printf("***Error in SecAsn1CoderCreate()\n"); + return -1; + } + + CSSM_X509_ALGORITHM_IDENTIFIER algParams; + memset(&algParams, 0, sizeof(algParams)); + algParams.algorithm = *paramOid; + CSSM_DATA encoded = {0, NULL}; + int ourRtn = 0; + if(SecAsn1EncodeItem(coder, &algParams, kSecAsn1AlgorithmIDTemplate, + &encoded)) { + printf("***Error encoding CSSM_X509_ALGORITHM_IDENTIFIER\n"); + ourRtn = -1; + goto errOut; + } + + /* That data is in the coder's memory space: copy ou9t to caller */ + if(appCopyCssmData(&encoded, params)) { + printf("***encodeParamOid malloc failure\n"); + ourRtn = -1; + } +errOut: + SecAsn1CoderRelease(coder); + return ourRtn; +} + +/* + * Cook up an unsigned cert. + * This is just a wrapper for CSSM_CL_CertCreateTemplate(). + */ + +#define ALWAYS_SET_VERSION 0 + +CSSM_DATA_PTR CB_MakeCertTemplate( + /* required */ + CSSM_CL_HANDLE clHand, + uint32 serialNumber, + const CSSM_X509_NAME *issuerName, + const CSSM_X509_NAME *subjectName, + const CSSM_X509_TIME *notBefore, + const CSSM_X509_TIME *notAfter, + const CSSM_KEY_PTR subjectPubKey, + CSSM_ALGORITHMS sigAlg, // e.g., CSSM_ALGID_SHA1WithRSA + /* optional */ + const CSSM_DATA *subjectUniqueId, + const CSSM_DATA *issuerUniqueId, + CSSM_X509_EXTENSION *extensions, + unsigned numExtensions) +{ + CSSM_FIELD *certTemp; + unsigned fieldDex = 0; // index into certTemp + CSSM_DATA_PTR serialDER = NULL; // serial number, DER format + CSSM_DATA_PTR rawCert; // from CSSM_CL_CertCreateTemplate + unsigned version = 0; + CSSM_DATA_PTR versionDER = NULL; + unsigned extNum; + int setVersion = ALWAYS_SET_VERSION; + const CSSM_OID *paramOid = NULL; + + /* convert uint32-style algorithm to the associated struct */ + CSSM_X509_ALGORITHM_IDENTIFIER algId; + switch(sigAlg) { + case CSSM_ALGID_SHA1WithRSA: + algId.algorithm = CSSMOID_SHA1WithRSA; + break; + case CSSM_ALGID_MD5WithRSA: + algId.algorithm = CSSMOID_MD5WithRSA; + break; + case CSSM_ALGID_MD2WithRSA: + algId.algorithm = CSSMOID_MD2WithRSA; + break; + case CSSM_ALGID_FEE_MD5: + algId.algorithm = CSSMOID_APPLE_FEE_MD5; + break; + case CSSM_ALGID_FEE_SHA1: + algId.algorithm = CSSMOID_APPLE_FEE_SHA1; + break; + case CSSM_ALGID_SHA1WithECDSA: + algId.algorithm = CSSMOID_ECDSA_WithSHA1; + break; + case CSSM_ALGID_SHA1WithDSA: + algId.algorithm = CSSMOID_SHA1WithDSA_CMS; + break; + case CSSM_ALGID_SHA224WithRSA: + algId.algorithm = CSSMOID_SHA224WithRSA; + break; + case CSSM_ALGID_SHA256WithRSA: + algId.algorithm = CSSMOID_SHA256WithRSA; + break; + case CSSM_ALGID_SHA384WithRSA: + algId.algorithm = CSSMOID_SHA384WithRSA; + break; + case CSSM_ALGID_SHA512WithRSA: + algId.algorithm = CSSMOID_SHA512WithRSA; + break; + /* These specify the digest algorithm via an additional parameter OID */ + case CSSM_ALGID_SHA224WithECDSA: + algId.algorithm = CSSMOID_ECDSA_WithSpecified; + paramOid = &CSSMOID_SHA224; + break; + case CSSM_ALGID_SHA256WithECDSA: + algId.algorithm = CSSMOID_ECDSA_WithSpecified; + paramOid = &CSSMOID_SHA256; + break; + case CSSM_ALGID_SHA384WithECDSA: + algId.algorithm = CSSMOID_ECDSA_WithSpecified; + paramOid = &CSSMOID_SHA384; + break; + case CSSM_ALGID_SHA512WithECDSA: + algId.algorithm = CSSMOID_ECDSA_WithSpecified; + paramOid = &CSSMOID_SHA512; + break; + default: + printf("CB_MakeCertTemplate: unknown sig alg (%u)\n", (unsigned)sigAlg); + return NULL; + } + if(paramOid != NULL) { + /* not-quite-trivial encoding of digest algorithm */ + if(encodeParamOid(paramOid, &algId.parameters)) { + return NULL; + } + } + else { + algId.parameters.Data = NULL; + algId.parameters.Length = 0; + } + + /* + * version, we infer + * serialNumber thru subjectPubKey + */ + unsigned numFields = 7 + numExtensions; + if(numExtensions) { + version = 2; + } + if(subjectUniqueId) { + numFields++; + if(version == 0) { + version = 1; + } + } + if(issuerUniqueId) { + numFields++; + if(version == 0) { + version = 1; + } + } + if(version > 0) { + setVersion = 1; + } + if(setVersion) { + numFields++; + } + + certTemp = (CSSM_FIELD *)CSSM_MALLOC(sizeof(CSSM_FIELD) * numFields); + + /* version */ + if(setVersion) { + versionDER = intToDER(version); + certTemp[fieldDex].FieldOid = CSSMOID_X509V1Version; + certTemp[fieldDex++].FieldValue = *versionDER; + } + + /* serial number */ + serialDER = intToDER(serialNumber); + certTemp[fieldDex].FieldOid = CSSMOID_X509V1SerialNumber; + certTemp[fieldDex++].FieldValue = *serialDER; + + /* subject and issuer name */ + certTemp[fieldDex].FieldOid = CSSMOID_X509V1IssuerNameCStruct; + certTemp[fieldDex].FieldValue.Data = (uint8 *)issuerName; + certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_NAME); + + certTemp[fieldDex].FieldOid = CSSMOID_X509V1SubjectNameCStruct; + certTemp[fieldDex].FieldValue.Data = (uint8 *)subjectName; + certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_NAME); + + /* not before/after */ + certTemp[fieldDex].FieldOid = CSSMOID_X509V1ValidityNotBefore; + certTemp[fieldDex].FieldValue.Data = (uint8 *)notBefore; + certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_TIME); + + certTemp[fieldDex].FieldOid = CSSMOID_X509V1ValidityNotAfter; + certTemp[fieldDex].FieldValue.Data = (uint8 *)notAfter; + certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_TIME); + + /* the subject key */ + certTemp[fieldDex].FieldOid = CSSMOID_CSSMKeyStruct; + certTemp[fieldDex].FieldValue.Data = (uint8 *)subjectPubKey; + certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_KEY); + + /* signature algorithm */ + certTemp[fieldDex].FieldOid = CSSMOID_X509V1SignatureAlgorithmTBS; + certTemp[fieldDex].FieldValue.Data = (uint8 *)&algId; + certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_ALGORITHM_IDENTIFIER); + + /* subject/issuer unique IDs */ + if(subjectUniqueId != 0) { + certTemp[fieldDex].FieldOid = CSSMOID_X509V1CertificateSubjectUniqueId; + certTemp[fieldDex++].FieldValue = *subjectUniqueId; + } + if(issuerUniqueId != 0) { + certTemp[fieldDex].FieldOid = CSSMOID_X509V1CertificateIssuerUniqueId; + certTemp[fieldDex++].FieldValue = *issuerUniqueId; + } + + for(extNum=0; extNumformat == CSSM_X509_DATAFORMAT_PARSED) { + certTemp[fieldDex].FieldOid = ext->extnId; + } + else { + certTemp[fieldDex].FieldOid = CSSMOID_X509V3CertificateExtensionCStruct; + } + certTemp[fieldDex].FieldValue.Data = (uint8 *)ext; + certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_EXTENSION); + } + if(fieldDex != numFields) { + printf("CB_MakeCertTemplate numFields screwup\n"); + return NULL; + } + + /* + * OK, here we go + */ + rawCert = (CSSM_DATA_PTR)CSSM_MALLOC(sizeof(CSSM_DATA)); + rawCert->Data = NULL; + rawCert->Length = 0; + CSSM_RETURN crtn = CSSM_CL_CertCreateTemplate(clHand, + fieldDex, + certTemp, + rawCert); + if(crtn) { + printError("CSSM_CL_CertCreateTemplate", crtn); + appFreeCssmData(rawCert, CSSM_TRUE); + rawCert = NULL; + } + + /* free the stuff we mallocd to get here */ + appFreeCssmData(serialDER, CSSM_TRUE); + appFreeCssmData(versionDER, CSSM_TRUE); + CSSM_FREE(certTemp); + if((paramOid != NULL) && (algId.parameters.Data != NULL)) { + CSSM_FREE(algId.parameters.Data); + } + return rawCert; +}