#include <stdlib.h>
#include <strings.h>
#include <stdio.h>
#include <unistd.h>
#include <Security/Security.h>
#include <Security/SecAsn1Coder.h>
#include <Security/SecAsn1Types.h>
#include <Security/X509Templates.h>
#include <Security/keyTemplates.h>
#include <Security/SecKeyPriv.h>
#include <Security/SecIdentityPriv.h>
#include <utilLib/common.h>
#include <security_cdsa_utils/cuFileIo.h>
#include <clAppUtils/timeStr.h>
#define THIS_UPDATE_DEF 0
#define NEXT_UPDATE_DEF (60 * 60 * 24)
#define REVOKE_TIME_DEF (60 * 60 * 12)
static void usage(char **argv)
{
printf("usage: %s [requiredParams...] [options...]\n", argv[0]);
printf("Required parameters:\n");
printf(" -s subjectCert\n");
printf(" -i issuerCert\n");
printf(" -o outputFile\n");
printf("Options:\n");
printf(" -k keychain -- contains issuerCert identity; default is default KC list\n");
printf(" -r revokeTime -- seconds after 'now' cert is revoked; default is %d\n",
REVOKE_TIME_DEF);
printf(" -t thisUpdate -- CRL thisUpdate, seconds after 'now'; default is %d\n",
THIS_UPDATE_DEF);
printf(" -n thisUpdate -- CRL nextUpdate, seconds after 'now'; default is %d\n",
NEXT_UPDATE_DEF);
exit(1);
}
static void secondsToNssTime(
int seconds,
NSS_Time *nssTime)
{
char *revocationDate = genTimeAtNowPlus(seconds);
nssTime->item.Data = (uint8 *)revocationDate;
nssTime->item.Length = strlen(revocationDate);
nssTime->tag = SEC_ASN1_GENERALIZED_TIME;
}
static OSStatus secSign(
SecKeyRef signingKey,
CSSM_ALGORITHMS sigAlg,
const CSSM_DATA *ptext,
CSSM_DATA *sig)
{
const CSSM_KEY *cssmKey;
CSSM_CSP_HANDLE cspHand;
const CSSM_ACCESS_CREDENTIALS *creds;
CSSM_CC_HANDLE sigHand = 0;
CSSM_RETURN crtn;
OSStatus ortn;
ortn = SecKeyGetCSSMKey(signingKey, &cssmKey);
if(ortn) {
cssmPerror("SecKeyGetCSSMKey", ortn);
return ortn;
}
ortn = SecKeyGetCSPHandle(signingKey, &cspHand);
if(ortn) {
cssmPerror("SecKeyGetCSPHandle", ortn);
return ortn;
}
ortn = SecKeyGetCredentials(signingKey,
CSSM_ACL_AUTHORIZATION_SIGN,
kSecCredentialTypeDefault,
&creds);
if(ortn) {
cssmPerror("SecKeyGetCredentials", ortn);
return ortn;
}
crtn = CSSM_CSP_CreateSignatureContext(cspHand,
sigAlg,
creds,
cssmKey,
&sigHand);
if(crtn) {
cssmPerror("CSSM_CSP_CreateSignatureContext", crtn);
return crtn;
}
sig->Data = NULL;
sig->Length = 0;
crtn = CSSM_SignData(sigHand,
ptext,
1,
CSSM_ALGID_NONE, sig);
CSSM_DeleteContext(sigHand);
return crtn;
}
static int makeCrl(
const unsigned char *subjectCert,
unsigned subjectCertLen,
SecKeyRef signingKey,
int revokeTime, int crlThisUpdate, int crlNextUpdate, unsigned char **crlOut, unsigned *crlOutLen) {
SecAsn1CoderRef coder = NULL;
OSStatus ortn;
int ourRtn = -1;
NSS_Certificate subject;
NSS_RevokedCert revokedCert;
NSS_TBSCrl tbsCrl;
NSS_SignedCertOrCRL crl;
CSSM_DATA encodedCrl = {0, NULL};
uint8 nullEnc[2] = {5, 0};
CSSM_DATA nullEncData = {2, nullEnc};
ortn = SecAsn1CoderCreate(&coder);
if(ortn) {
cssmPerror("SecAsn1CoderCreate", ortn);
goto errOut;
}
memset(&subject, 0, sizeof(subject));
ortn = SecAsn1Decode(coder, subjectCert, subjectCertLen, kSecAsn1SignedCertTemplate,
&subject);
if(ortn) {
cssmPerror("SecAsn1Decode(subjectCert)", ortn);
goto errOut;
}
revokedCert.userCertificate = subject.tbs.serialNumber;
secondsToNssTime(revokeTime, &revokedCert.revocationDate);
revokedCert.extensions = NULL;
memset(&tbsCrl, 0, sizeof(tbsCrl));
tbsCrl.signature.algorithm = CSSMOID_SHA1WithRSA;
tbsCrl.signature.parameters = nullEncData;
tbsCrl.issuer = subject.tbs.issuer;
secondsToNssTime(crlThisUpdate, &tbsCrl.thisUpdate);
secondsToNssTime(crlNextUpdate, &tbsCrl.nextUpdate);
tbsCrl.revokedCerts = (NSS_RevokedCert **)(SecAsn1Malloc(coder, sizeof(void *) * 2));
tbsCrl.revokedCerts[0] = &revokedCert;
tbsCrl.revokedCerts[1] = NULL;
tbsCrl.extensions = NULL;
memset(&crl, 0, sizeof(crl));
ortn = SecAsn1EncodeItem(coder, &tbsCrl, kSecAsn1TBSCrlTemplate, &crl.tbsBlob);
if(ortn) {
cssmPerror("SecAsn1EncodeItem(tbsCrl)", ortn);
goto errOut;
}
ortn = SecAsn1EncodeItem(coder, &tbsCrl.signature,
kSecAsn1AlgorithmIDTemplate, &crl.signatureAlgorithm);
if(ortn) {
cssmPerror("SecAsn1EncodeItem(signatureAlgorithm)", ortn);
goto errOut;
}
ortn = secSign(signingKey, CSSM_ALGID_SHA1WithRSA, &crl.tbsBlob,
&crl.signature);
if(ortn) {
goto errOut;
}
crl.signature.Length *= 8;
ortn = SecAsn1EncodeItem(coder, &crl,
kSecAsn1SignedCertOrCRLTemplate, &encodedCrl);
if(ortn) {
cssmPerror("SecAsn1EncodeItem(encodedCrl)", ortn);
goto errOut;
}
*crlOut = (unsigned char *)malloc(encodedCrl.Length);
*crlOut = (unsigned char *)encodedCrl.Data;
*crlOutLen = encodedCrl.Length;
ourRtn = 0;
errOut:
if(coder) {
SecAsn1CoderRelease(coder);
}
if(revokedCert.revocationDate.item.Data) {
CSSM_FREE(revokedCert.revocationDate.item.Data);
}
if(tbsCrl.thisUpdate.item.Data) {
CSSM_FREE(tbsCrl.thisUpdate.item.Data);
}
if(revokedCert.revocationDate.item.Data) {
CSSM_FREE(tbsCrl.nextUpdate.item.Data);
}
return ourRtn;
}
int main(int argc, char **argv)
{
char *subjectName = NULL;
char *issuerName = NULL;
char *outFileName = NULL;
char *kcName = NULL;
int revokeTime = REVOKE_TIME_DEF;
int thisUpdate = THIS_UPDATE_DEF;
int nextUpdate = NEXT_UPDATE_DEF;
extern char *optarg;
int arg;
while ((arg = getopt(argc, argv, "s:i:o:k:r:t:n:h")) != -1) {
switch (arg) {
case 's':
subjectName = optarg;
break;
case 'i':
issuerName = optarg;
break;
case 'o':
outFileName = optarg;
break;
case 'k':
kcName = optarg;
break;
case 'r':
revokeTime = atoi(optarg);
break;
case 't':
thisUpdate = atoi(optarg);
break;
case 'n':
nextUpdate = atoi(optarg);
break;
default:
case 'h':
usage(argv);
}
}
if(optind != argc) {
usage(argv);
}
if((subjectName == NULL) || (issuerName == NULL) || (outFileName == NULL)) {
usage(argv);
}
unsigned char *subjectCert;
unsigned subjectCertLen;
unsigned char *issuerCert;
unsigned issuerCertLen;
if(readFile(subjectName, &subjectCert, &subjectCertLen)) {
printf("***Error reading %s. \n", subjectName);
exit(1);
}
if(readFile(issuerName, &issuerCert, &issuerCertLen)) {
printf("***Error reading %s. \n", issuerName);
exit(1);
}
SecKeychainRef kcRef = NULL;
OSStatus ortn;
if(kcName) {
ortn = SecKeychainOpen(kcName, &kcRef);
if(ortn) {
cssmPerror("SecKeychainOpen", ortn);
exit(1);
}
}
SecCertificateRef certRef = NULL;
SecIdentityRef idRef = NULL;
SecKeyRef signingKey = NULL;
CSSM_DATA issuerCData = {issuerCertLen, (uint8 *)issuerCert};
ortn = SecCertificateCreateFromData(&issuerCData,
CSSM_CERT_X_509v3,
CSSM_CERT_ENCODING_DER,
&certRef);
if(ortn) {
cssmPerror("SecCertificateCreateFromData", ortn);
exit(1);
}
ortn = SecIdentityCreateWithCertificate(kcRef, certRef, &idRef);
if(ortn) {
cssmPerror("SecIdentityCreateWithCertificate", ortn);
exit(1);
}
ortn = SecIdentityCopyPrivateKey(idRef, &signingKey);
if(ortn) {
cssmPerror("SecIdentityCopyPrivateKey", ortn);
exit(1);
}
unsigned char *crlOut = NULL;
unsigned crlOutLen = 0;
if(makeCrl(subjectCert, subjectCertLen,
signingKey,
revokeTime, thisUpdate, nextUpdate,
&crlOut, &crlOutLen)) {
printf("***Error creating CRL. Aborting.\n");
exit(1);
}
if(writeFile(outFileName, crlOut, crlOutLen)) {
printf("***Error writing CRL to %s\n", outFileName);
}
else {
printf("...wrote %u bytes to %s.\n", crlOutLen, outFileName);
}
return 0;
}