--- /dev/null
+/*
+ * rsatool.c - RSA/DSA/ECDSA key pair generator, en/decrypt, sign/verify with file I/O
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <Security/cssm.h>
+#include "cspwrap.h"
+#include "common.h"
+#include <security_cdsa_utils/cuFileIo.h>
+
+/* For 3141770 - defined true when PR-3074739 merged to TOT Security */
+#define OPENSSL_ENABLE 1
+
+#define USAGE_NAME "noUsage"
+#define USAGE_NAME_LEN (strlen(USAGE_NAME))
+#define DEFAULT_KEY_SIZE_BITS 512
+
+typedef struct {
+ CSSM_ALGORITHMS alg;
+ uint32 keySizeInBits;
+ CSSM_CSP_HANDLE cspHand;
+ char *keyFileName;
+ char *outKeyFileName; // for pub key convert
+ char *plainFileName;
+ char *sigFileName;
+ char *cipherFileName;
+ char *dsaParamFileIn;
+ char *dsaParamFileOut;
+ CSSM_BOOL swapKeyClass;
+ CSSM_BOOL rawSign;
+ CSSM_BOOL noPad;
+ CSSM_BOOL quiet;
+ CSSM_KEYBLOB_FORMAT pubKeyFormat; // FORMAT_NONE ==> default
+ CSSM_KEYBLOB_FORMAT privKeyFormat; // FORMAT_NONE ==> default
+ CSSM_KEYBLOB_FORMAT outPubKeyFormat;// FORMAT_NONE ==> default, for pub key convert
+ CSSM_ALGORITHMS digestAlg; // optional digest alg for raw sign/verify
+} opParams;
+
+static void usage(char **argv)
+{
+ printf("usage: %s op [options]\n", argv[0]);
+ printf(" op:\n");
+ printf(" g generate key pair\n");
+ printf(" e encrypt\n");
+ printf(" d decrypt\n");
+ printf(" s sign\n");
+ printf(" v verify\n");
+ printf(" S SHA-1 digest\n");
+ printf(" M MD5 digest\n");
+ printf(" C convert public key format\n");
+ printf(" options:\n");
+ printf(" k=keyfileBase keys are keyFileBase_pub.der, "
+ "keyFileBase_priv.der)\n");
+ printf(" K=outputPublicKey\n");
+ printf(" p=plainFile\n");
+ printf(" c=cipherFile\n");
+ printf(" s=sigfile\n");
+ printf(" z=keySizeInBits (default %d)\n", DEFAULT_KEY_SIZE_BITS);
+ printf(" w (swap key class)\n");
+ printf(" r (raw sign/verify)\n");
+ printf(" P (no padding)\n");
+ printf(" d=digestAlg digestAlg: s(SHA1) 5(MD5) for raw signing\n");
+ printf(" m=dsaParamFileIn\n");
+ printf(" M=dsaParamFileOut (must specify one of dsaParamFile{In,Out}\n");
+ printf(" b=[1xboOL] (pub key in PKCS1/X509/BSAFE/OpenSSH1/OpenSSH2/OpenSSL form)\n");
+ printf(" RSA = {PKCS1,X509,OpenSSH1,OpenSSH2} default = PKCS1\n");
+ printf(" DSA = {BSAFE,X509,OpenSSH2} default = X509\n");
+ printf(" ECDSA = {X509, OpenSSL} default = X509\n");
+ printf(" Note: RSA and DSA public keys in OpenSSL form are X509.\n");
+ printf(" v=[18sbo] (priv key in PKCS1/PKCS8/OpenSSH/BSAFE/OpenSSL form)\n");
+ printf(" RSA = {PKCS1,PKCS8,OpenSSH1} default = PKCS8\n");
+ printf(" DSA = {BSAFE,OpenSSL,PKCS8} default = OpenSSL\n");
+ printf(" ECDSA = {PKCS8,OpenSSL} default = OpenSSL}\n");
+ printf(" Note: RSA private key in OpenSSL form is PKCS1.\n");
+ printf(" B=[1xboO] output public key format\n");
+ printf(" a=alg d=DSA, r=RSA, e=ECDSA; default = RSA\n");
+ printf(" q(uiet)\n");
+ exit(1);
+}
+
+/* NULL wrap a key to specified format. */
+static CSSM_RETURN nullWrapKey(CSSM_CSP_HANDLE cspHand,
+ const CSSM_KEY *refKey,
+ CSSM_KEYBLOB_FORMAT blobFormat,
+ CSSM_KEY_PTR rawKey) // RETURNED
+{
+ CSSM_CC_HANDLE ccHand;
+ CSSM_RETURN crtn;
+ CSSM_ACCESS_CREDENTIALS creds;
+ CSSM_DATA descData = {0, 0};
+
+ memset(rawKey, 0, sizeof(CSSM_KEY));
+ memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
+ crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
+ CSSM_ALGID_NONE,
+ CSSM_ALGMODE_NONE,
+ &creds, // passPhrase
+ NULL, // unwrappingKey
+ NULL, // initVector
+ CSSM_PADDING_NONE,
+ 0, // Params
+ &ccHand);
+ if(crtn) {
+ printError("cspWrapKey/CreateContext", crtn);
+ return crtn;
+ }
+ if(blobFormat != CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) {
+ /* only add this attribute if it's not the default */
+ CSSM_ATTRIBUTE_TYPE attrType;
+
+ switch(refKey->KeyHeader.KeyClass) {
+ case CSSM_KEYCLASS_SESSION_KEY:
+ attrType = CSSM_ATTRIBUTE_SYMMETRIC_KEY_FORMAT;
+ break;
+ case CSSM_KEYCLASS_PUBLIC_KEY:
+ attrType = CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT;
+ break;
+ case CSSM_KEYCLASS_PRIVATE_KEY:
+ attrType = CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT;
+ break;
+ default:
+ printf("***Bogus KeyClass in nullWrapKey\n");
+ return -1;
+ }
+ CSSM_CONTEXT_ATTRIBUTE attr;
+ attr.AttributeType = attrType;
+ attr.AttributeLength = sizeof(uint32);
+ attr.Attribute.Uint32 = blobFormat;
+ crtn = CSSM_UpdateContextAttributes(
+ ccHand,
+ 1,
+ &attr);
+ if(crtn) {
+ printError("CSSM_UpdateContextAttributes", crtn);
+ return crtn;
+ }
+ }
+ crtn = CSSM_WrapKey(ccHand,
+ &creds,
+ refKey,
+ &descData,
+ rawKey);
+ if(crtn != CSSM_OK) {
+ printError("CSSM_WrapKey", crtn);
+ }
+ if(CSSM_DeleteContext(ccHand)) {
+ printf("CSSM_DeleteContext failure\n");
+ }
+ return crtn;
+}
+
+/*
+ * Sign/verify optional "no padding" context attr
+ */
+static CSSM_RETURN sigSign(CSSM_CSP_HANDLE cspHand,
+ uint32 algorithm, // CSSM_ALGID_FEE_MD5, etc.
+ CSSM_KEY_PTR key, // private key
+ const CSSM_DATA *text,
+ CSSM_DATA_PTR sig,
+ uint32 digestAlg, // optional for raw signing
+ CSSM_BOOL noPad) // true --> add PADDING_NONE to context
+{
+ CSSM_CC_HANDLE sigHand;
+ CSSM_RETURN crtn;
+
+ crtn = CSSM_CSP_CreateSignatureContext(cspHand,
+ algorithm,
+ NULL, // passPhrase
+ key,
+ &sigHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateSignatureContext", crtn);
+ return crtn;
+ }
+ if(noPad) {
+ crtn = AddContextAttribute(sigHand,
+ CSSM_ATTRIBUTE_PADDING,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ CSSM_PADDING_NONE);
+ if(crtn) {
+ return crtn;
+ }
+ }
+ crtn = CSSM_SignData(sigHand,
+ text,
+ 1,
+ digestAlg,
+ sig);
+ if(crtn) {
+ printError("CSSM_SignData", crtn);
+ }
+ CSSM_DeleteContext(sigHand);
+ return crtn;
+}
+
+static CSSM_RETURN sigVerify(CSSM_CSP_HANDLE cspHand,
+ uint32 algorithm, // CSSM_ALGID_FEE_MD5, etc.
+ CSSM_KEY_PTR key, // public key
+ const CSSM_DATA *text,
+ const CSSM_DATA *sig,
+ uint32 digestAlg, // optional for raw signing
+ CSSM_BOOL noPad) // true --> add PADDING_NONE to context
+{
+ CSSM_CC_HANDLE sigHand;
+ CSSM_RETURN crtn;
+
+ crtn = CSSM_CSP_CreateSignatureContext(cspHand,
+ algorithm,
+ NULL, // passPhrase
+ key,
+ &sigHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateSignatureContext", crtn);
+ return crtn;
+ }
+ if(noPad) {
+ crtn = AddContextAttribute(sigHand,
+ CSSM_ATTRIBUTE_PADDING,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ CSSM_PADDING_NONE);
+ if(crtn) {
+ return crtn;
+ }
+ }
+ crtn = CSSM_VerifyData(sigHand,
+ text,
+ 1,
+ digestAlg,
+ sig);
+ if(crtn) {
+ printError("CSSM_VerifyData", crtn);
+ }
+ CSSM_DeleteContext(sigHand);
+ return crtn;
+}
+
+/*
+ * Generate DSA key pair. Algorithm parameters are
+ * either specified by caller via inParams, or are generated here
+ * and returned to caller in outParams. Exactly one of (inParams,
+ * outParams) must be non-NULL.
+ */
+static CSSM_RETURN genDsaKeyPair(
+ CSSM_CSP_HANDLE cspHand,
+ const char *keyLabel,
+ unsigned keyLabelLen,
+ uint32 keySize, // in bits
+ CSSM_KEY_PTR pubKey, // mallocd by caller
+ CSSM_BOOL pubIsRef, // true - reference key, false - data
+ uint32 pubKeyUsage, // CSSM_KEYUSE_ENCRYPT, etc.
+ CSSM_KEYBLOB_FORMAT pubFormat, // Optional. Some algorithms (currently, FEE)
+ // provide for multiple key blob formats.
+ // Specify 0 or CSSM_KEYBLOB_RAW_FORMAT_NONE
+ // to get the default format.
+ CSSM_KEY_PTR privKey, // mallocd by caller
+ CSSM_BOOL privIsRef, // true - reference key, false - data
+ uint32 privKeyUsage, // CSSM_KEYUSE_DECRYPT, etc.
+ CSSM_KEYBLOB_FORMAT privFormat, // optional 0 ==> default
+ const CSSM_DATA *inParams, // optional
+ CSSM_DATA_PTR outParams) // optional, we malloc
+{
+ CSSM_RETURN crtn;
+ CSSM_CC_HANDLE ccHand;
+ CSSM_DATA keyLabelData;
+ uint32 pubAttr;
+ uint32 privAttr;
+ CSSM_RETURN ocrtn = CSSM_OK;
+
+ /* Caller must specify either inParams or outParams, not both */
+ if(inParams && outParams) {
+ return CSSMERR_CSSM_INVALID_POINTER;
+ }
+ if(!inParams && !outParams) {
+ return CSSMERR_CSSM_INVALID_POINTER;
+ }
+
+ keyLabelData.Data = (uint8 *)keyLabel,
+ keyLabelData.Length = keyLabelLen;
+ memset(pubKey, 0, sizeof(CSSM_KEY));
+ memset(privKey, 0, sizeof(CSSM_KEY));
+
+ crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
+ CSSM_ALGID_DSA,
+ keySize,
+ NULL, // Seed
+ NULL, // Salt
+ NULL, // StartDate
+ NULL, // EndDate
+ inParams, // Params, may be NULL
+ &ccHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateKeyGenContext", crtn);
+ return crtn;
+ }
+ /* cook up attribute bits */
+ if(pubIsRef) {
+ pubAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
+ }
+ else {
+ pubAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
+ }
+ if(privIsRef) {
+ privAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
+ }
+ else {
+ privAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
+ }
+
+ if(outParams) {
+ /* explicitly generate params and return them to caller */
+ outParams->Data = NULL;
+ outParams->Length = 0;
+ crtn = CSSM_GenerateAlgorithmParams(ccHand,
+ keySize, outParams);
+ if(crtn) {
+ printError("CSSM_GenerateAlgorithmParams", crtn);
+ CSSM_DeleteContext(ccHand);
+ return crtn;
+ }
+ }
+
+ /* optional format specifiers */
+ if(pubFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE) {
+ crtn = AddContextAttribute(ccHand,
+ CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ pubFormat);
+ if(crtn) {
+ printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT)", crtn);
+ return crtn;
+ }
+ }
+ if(privFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE) {
+ crtn = AddContextAttribute(ccHand,
+ CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ privFormat);
+ if(crtn) {
+ printError("AddContextAttribute(CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT)", crtn);
+ return crtn;
+ }
+ }
+ crtn = CSSM_GenerateKeyPair(ccHand,
+ pubKeyUsage,
+ pubAttr,
+ &keyLabelData,
+ pubKey,
+ privKeyUsage,
+ privAttr,
+ &keyLabelData, // same labels
+ NULL, // CredAndAclEntry
+ privKey);
+ if(crtn) {
+ printError("CSSM_GenerateKeyPair", crtn);
+ ocrtn = crtn;
+ }
+ if(ccHand != 0) {
+ crtn = CSSM_DeleteContext(ccHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ }
+ }
+ return ocrtn;
+}
+
+/*
+ * Given keyFileBase, obtain name of public or private name. Output names
+ * mallocd by caller.
+ */
+#define KEY_FILE_NAME_MAX_LEN 256
+
+static void rtKeyFileName(
+ const char *keyFileBase,
+ CSSM_BOOL isPub,
+ char *outFileName)
+{
+ if(isPub) {
+ sprintf(outFileName, "%s_pub.der", keyFileBase);
+ }
+ else {
+ sprintf(outFileName, "%s_priv.der", keyFileBase);
+ }
+}
+
+/*
+ * Given keyFileBase and key type, init a CSSM_KEY.
+ */
+static int rt_readKey(
+ CSSM_CSP_HANDLE cspHand,
+ const char *keyFileBase,
+ CSSM_BOOL isPub,
+ CSSM_ALGORITHMS alg,
+ CSSM_KEYBLOB_FORMAT format, // FORMAT_NONE ==> default
+ CSSM_KEY_PTR key)
+{
+ char fileName[KEY_FILE_NAME_MAX_LEN];
+ int irtn;
+ CSSM_DATA_PTR keyData = &key->KeyData;
+ CSSM_KEYHEADER_PTR hdr = &key->KeyHeader;
+ CSSM_RETURN crtn;
+ CSSM_KEY_SIZE keySize;
+ unsigned len;
+
+ memset(key, 0, sizeof(CSSM_KEY));
+ rtKeyFileName(keyFileBase, isPub, fileName);
+ irtn = readFile(fileName, &keyData->Data, &len);
+ if(irtn) {
+ printf("***error %d reading key file %s\n", irtn, fileName);
+ return irtn;
+ }
+ keyData->Length = len;
+ hdr->HeaderVersion = CSSM_KEYHEADER_VERSION;
+ hdr->BlobType = CSSM_KEYBLOB_RAW;
+ hdr->Format = format;
+ hdr->AlgorithmId = alg;
+ hdr->KeyClass = isPub ? CSSM_KEYCLASS_PUBLIC_KEY :
+ CSSM_KEYCLASS_PRIVATE_KEY;
+ hdr->KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
+ hdr->KeyUsage = CSSM_KEYUSE_ANY;
+
+ /* ask the CSP for key size */
+ crtn = CSSM_QueryKeySizeInBits(cspHand, 0, key, &keySize);
+ if(crtn) {
+ printError("CSSM_QueryKeySizeInBits", crtn);
+ return 1;
+ }
+ hdr->LogicalKeySizeInBits = keySize.LogicalKeySizeInBits;
+ return 0;
+}
+
+static int rt_generate(opParams *op)
+{
+ CSSM_RETURN crtn;
+ CSSM_KEY pubKey;
+ CSSM_KEY privKey;
+ char fileName[KEY_FILE_NAME_MAX_LEN];
+ int irtn;
+ CSSM_DATA paramIn = {0, NULL};
+ CSSM_DATA paramOut = {0, NULL};
+ CSSM_DATA_PTR paramInPtr = NULL;
+ CSSM_DATA_PTR paramOutPtr = NULL;
+
+ if(op->keyFileName == NULL) {
+ printf("***Need a keyFileName to generate key pair.\n");
+ return 1;
+ }
+ memset(&pubKey, 0, sizeof(CSSM_KEY));
+ memset(&privKey, 0, sizeof(CSSM_KEY));
+
+ if(op->alg == CSSM_ALGID_DSA) {
+ /* must specify either inParams or outParams, not both */
+ if(op->dsaParamFileIn && op->dsaParamFileOut) {
+ printf("***DSA key generation requires one parameter file spec.\n");
+ return 1;
+ }
+ if(!op->dsaParamFileIn && !op->dsaParamFileOut) {
+ printf("***DSA key generation requires one parameter file spec.\n");
+ return 1;
+ }
+ if(op->dsaParamFileIn) {
+ /* caller-specified params */
+ unsigned len;
+ irtn = readFile(op->dsaParamFileIn, ¶mIn.Data, &len);
+ if(irtn) {
+ printf("***Error reading DSA params from %s. Aborting.\n",
+ op->dsaParamFileIn);
+ }
+ paramIn.Length = len;
+ paramInPtr = ¶mIn;
+ }
+ else {
+ /* generate params --> paramOut */
+ paramOutPtr = ¶mOut;
+ }
+ crtn = genDsaKeyPair(op->cspHand,
+ USAGE_NAME,
+ USAGE_NAME_LEN,
+ op->keySizeInBits,
+ &pubKey,
+ CSSM_FALSE, // not ref
+ CSSM_KEYUSE_VERIFY, // not really important
+ op->pubKeyFormat,
+ &privKey,
+ CSSM_FALSE, // not ref
+ CSSM_KEYUSE_SIGN,
+ op->privKeyFormat,
+ paramInPtr,
+ paramOutPtr);
+ if(crtn) {
+ return 1;
+ }
+ if(paramOutPtr) {
+ irtn = writeFile(op->dsaParamFileOut, paramOut.Data, paramOut.Length);
+ if(irtn) {
+ printf("***Error writing DSA params to %s. Aborting.\n",
+ op->dsaParamFileOut);
+ return 1;
+ }
+ if(!op->quiet) {
+ printf("...wrote %lu bytes to %s\n", paramOut.Length,
+ op->dsaParamFileOut);
+ }
+ CSSM_FREE(paramOut.Data);
+ }
+ else {
+ /* mallocd by readFile() */
+ free(paramIn.Data);
+ }
+ }
+ else {
+ /* RSA, ECDSA */
+ crtn = cspGenKeyPair(op->cspHand,
+ op->alg,
+ USAGE_NAME,
+ USAGE_NAME_LEN,
+ op->keySizeInBits,
+ &pubKey,
+ CSSM_FALSE, // not ref
+ CSSM_KEYUSE_VERIFY, // not really important
+ op->pubKeyFormat,
+ &privKey,
+ CSSM_FALSE, // not ref
+ CSSM_KEYUSE_SIGN,
+ op->privKeyFormat,
+ CSSM_FALSE); // genSeed, not used here
+ if(crtn) {
+ return 1;
+ }
+ }
+
+ /* write the blobs */
+ rtKeyFileName(op->keyFileName, CSSM_TRUE, fileName);
+ irtn = writeFile(fileName, pubKey.KeyData.Data, pubKey.KeyData.Length);
+ if(irtn) {
+ printf("***Error %d writing to %s\n", irtn, fileName);
+ return irtn;
+ }
+ if(!op->quiet) {
+ printf("...wrote %lu bytes to %s\n", pubKey.KeyData.Length, fileName);
+ }
+ rtKeyFileName(op->keyFileName, CSSM_FALSE, fileName);
+ irtn = writeFile(fileName, privKey.KeyData.Data, privKey.KeyData.Length);
+ if(irtn) {
+ printf("***Error %d writing to %s\n", irtn, fileName);
+ return irtn;
+ }
+ if(!op->quiet) {
+ printf("...wrote %lu bytes to %s\n", privKey.KeyData.Length, fileName);
+ }
+ cspFreeKey(op->cspHand, &pubKey);
+ cspFreeKey(op->cspHand, &privKey);
+ return 0;
+}
+
+/* encrypt using public key */
+static int rt_encrypt(opParams *op)
+{
+ CSSM_KEY pubKey;
+ int irtn;
+ CSSM_DATA ptext;
+ CSSM_DATA ctext;
+ CSSM_RETURN crtn;
+ CSSM_BOOL isPub;
+ CSSM_ENCRYPT_MODE mode = CSSM_ALGMODE_NONE;
+ CSSM_KEYBLOB_FORMAT format = op->pubKeyFormat;
+ unsigned len;
+
+ if(op->keyFileName == NULL) {
+ printf("***Need a keyFileName to encrypt.\n");
+ return 1;
+ }
+ if((op->plainFileName == NULL) || (op->cipherFileName == NULL)) {
+ printf("***Need plainFileName and cipherFileName to encrypt.\n");
+ return 1;
+ }
+ if(op->swapKeyClass) {
+ isPub = CSSM_FALSE;
+ mode = CSSM_ALGMODE_PRIVATE_KEY;
+ format = op->privKeyFormat;
+ }
+ else {
+ isPub = CSSM_TRUE;
+ }
+ irtn = rt_readKey(op->cspHand, op->keyFileName, isPub, op->alg,
+ format, &pubKey);
+ if(irtn) {
+ return irtn;
+ }
+ irtn = readFile(op->plainFileName, &ptext.Data, &len);
+ if(irtn) {
+ printf("***Error reading %s\n", op->plainFileName);
+ return irtn;
+ }
+ ptext.Length = len;
+ ctext.Data = NULL;
+ ctext.Length = 0;
+
+ crtn = cspEncrypt(op->cspHand,
+ op->alg,
+ mode,
+ op->noPad ? CSSM_PADDING_NONE : CSSM_PADDING_PKCS1,
+ &pubKey,
+ NULL,
+ 0, // effectiveKeySize
+ 0, // rounds
+ NULL, // initVector
+ &ptext,
+ &ctext,
+ CSSM_FALSE); // mallocCtext
+ if(crtn) {
+ printError("cspEncrypt", crtn);
+ return 1;
+ }
+ irtn = writeFile(op->cipherFileName, ctext.Data, ctext.Length);
+ if(irtn) {
+ printf("***Error writing %s\n", op->cipherFileName);
+ }
+ else {
+ if(!op->quiet) {
+ printf("...wrote %lu bytes to %s\n", ctext.Length, op->cipherFileName);
+ }
+ }
+
+ free(pubKey.KeyData.Data); // allocd by rt_readKey --> readFile
+ free(ptext.Data); // allocd by readFile
+ appFreeCssmData(&ctext, CSSM_FALSE); // by CSP
+ return irtn;
+}
+
+/* decrypt using private key */
+static int rt_decrypt(opParams *op)
+{
+ CSSM_KEY privKey;
+ int irtn;
+ CSSM_DATA ptext;
+ CSSM_DATA ctext;
+ CSSM_RETURN crtn;
+ CSSM_BOOL isPub;
+ CSSM_ENCRYPT_MODE mode = CSSM_ALGMODE_NONE;
+ CSSM_KEYBLOB_FORMAT format = op->privKeyFormat;
+ unsigned len;
+
+ if(op->keyFileName == NULL) {
+ printf("***Need a keyFileName to decrypt.\n");
+ return 1;
+ }
+ if((op->plainFileName == NULL) || (op->cipherFileName == NULL)) {
+ printf("***Need plainFileName and cipherFileName to decrypt.\n");
+ return 1;
+ }
+ if(op->swapKeyClass) {
+ isPub = CSSM_TRUE;
+ mode = CSSM_ALGMODE_PUBLIC_KEY;
+ format = op->pubKeyFormat;
+ }
+ else {
+ isPub = CSSM_FALSE;
+ }
+ irtn = rt_readKey(op->cspHand, op->keyFileName, isPub, op->alg,
+ format, &privKey);
+ if(irtn) {
+ return irtn;
+ }
+ irtn = readFile(op->cipherFileName, &ctext.Data, &len);
+ if(irtn) {
+ printf("***Error reading %s\n", op->cipherFileName);
+ return irtn;
+ }
+ ctext.Length = len;
+ ptext.Data = NULL;
+ ptext.Length = 0;
+
+ crtn = cspDecrypt(op->cspHand,
+ op->alg,
+ mode,
+ op->noPad ? CSSM_PADDING_NONE : CSSM_PADDING_PKCS1,
+ &privKey,
+ NULL,
+ 0, // effectiveKeySize
+ 0, // rounds
+ NULL, // initVector
+ &ctext,
+ &ptext,
+ CSSM_FALSE); // mallocCtext
+ if(crtn) {
+ return 1;
+ }
+ irtn = writeFile(op->plainFileName, ptext.Data, ptext.Length);
+ if(irtn) {
+ printf("***Error writing %s\n", op->cipherFileName);
+ }
+ else {
+ if(!op->quiet) {
+ printf("...wrote %lu bytes to %s\n", ptext.Length, op->plainFileName);
+ }
+ }
+ free(privKey.KeyData.Data); // allocd by rt_readKey --> readFile
+ free(ctext.Data); // allocd by readFile
+ appFreeCssmData(&ptext, CSSM_FALSE); // by CSP
+ return irtn;
+}
+
+static int rt_sign(opParams *op)
+{
+ CSSM_KEY privKey;
+ int irtn;
+ CSSM_DATA ptext;
+ CSSM_DATA sig;
+ CSSM_RETURN crtn;
+ CSSM_ALGORITHMS alg;
+ unsigned len;
+
+ if(op->keyFileName == NULL) {
+ printf("***Need a keyFileName to sign.\n");
+ return 1;
+ }
+ if((op->plainFileName == NULL) || (op->sigFileName == NULL)) {
+ printf("***Need plainFileName and sigFileName to sign.\n");
+ return 1;
+ }
+ irtn = rt_readKey(op->cspHand, op->keyFileName, CSSM_FALSE, op->alg,
+ op->privKeyFormat, &privKey);
+ if(irtn) {
+ return irtn;
+ }
+ irtn = readFile(op->plainFileName, &ptext.Data, &len);
+ if(irtn) {
+ printf("***Error reading %s\n", op->plainFileName);
+ return irtn;
+ }
+ ptext.Length = len;
+ sig.Data = NULL;
+ sig.Length = 0;
+ switch(op->alg) {
+ case CSSM_ALGID_RSA:
+ if(op->rawSign) {
+ alg = CSSM_ALGID_RSA;
+ }
+ else {
+ alg = CSSM_ALGID_SHA1WithRSA;
+ }
+ break;
+ case CSSM_ALGID_DSA:
+ alg = CSSM_ALGID_SHA1WithDSA;
+ break;
+ case CSSM_ALGID_ECDSA:
+ if(op->rawSign) {
+ alg = CSSM_ALGID_ECDSA;
+ }
+ else {
+ alg = CSSM_ALGID_SHA1WithECDSA;
+ }
+ break;
+ default:
+ printf("Hey! Try another alg!\n");
+ exit(1);
+ }
+ crtn = sigSign(op->cspHand,
+ alg,
+ &privKey,
+ &ptext,
+ &sig,
+ op->digestAlg,
+ op->noPad);
+ if(crtn) {
+ printError("cspSign", crtn);
+ return 1;
+ }
+ irtn = writeFile(op->sigFileName, sig.Data, sig.Length);
+ if(irtn) {
+ printf("***Error writing %s\n", op->sigFileName);
+ }
+ else if(!op->quiet) {
+ printf("...wrote %lu bytes to %s\n", sig.Length, op->sigFileName);
+ }
+ free(privKey.KeyData.Data); // allocd by rt_readKey --> readFile
+ free(ptext.Data); // allocd by readFile
+ appFreeCssmData(&sig, CSSM_FALSE); // by CSP
+ return irtn;
+}
+
+static int rt_verify(opParams *op)
+{
+ CSSM_KEY pubKey;
+ int irtn;
+ CSSM_DATA ptext;
+ CSSM_DATA sig;
+ CSSM_RETURN crtn;
+ CSSM_ALGORITHMS alg;
+ unsigned len;
+
+ if(op->keyFileName == NULL) {
+ printf("***Need a keyFileName to verify.\n");
+ return 1;
+ }
+ if((op->plainFileName == NULL) || (op->sigFileName == NULL)) {
+ printf("***Need plainFileName and sigFileName to verify.\n");
+ return 1;
+ }
+ irtn = rt_readKey(op->cspHand, op->keyFileName, CSSM_TRUE, op->alg,
+ op->pubKeyFormat, &pubKey);
+ if(irtn) {
+ return irtn;
+ }
+ irtn = readFile(op->plainFileName, &ptext.Data, &len);
+ if(irtn) {
+ printf("***Error reading %s\n", op->plainFileName);
+ return irtn;
+ }
+ ptext.Length = len;
+ irtn = readFile(op->sigFileName, &sig.Data, (unsigned *)&sig.Length);
+ if(irtn) {
+ printf("***Error reading %s\n", op->sigFileName);
+ return irtn;
+ }
+ switch(op->alg) {
+ case CSSM_ALGID_RSA:
+ if(op->rawSign) {
+ alg = CSSM_ALGID_RSA;
+ }
+ else {
+ alg = CSSM_ALGID_SHA1WithRSA;
+ }
+ break;
+ case CSSM_ALGID_DSA:
+ alg = CSSM_ALGID_SHA1WithDSA;
+ break;
+ case CSSM_ALGID_ECDSA:
+ if(op->rawSign) {
+ alg = CSSM_ALGID_ECDSA;
+ }
+ else {
+ alg = CSSM_ALGID_SHA1WithECDSA;
+ }
+ break;
+ default:
+ printf("Hey! Try another alg!\n");
+ exit(1);
+ }
+ crtn = sigVerify(op->cspHand,
+ alg,
+ &pubKey,
+ &ptext,
+ &sig,
+ op->digestAlg,
+ op->noPad);
+ if(crtn) {
+ printError("sigVerify", crtn);
+ irtn = 1;
+ }
+ else if(!op->quiet){
+ printf("...signature verifies OK\n");
+ irtn = 0;
+ }
+ free(pubKey.KeyData.Data); // allocd by rt_readKey --> readFile
+ free(ptext.Data); // allocd by readFile
+ free(sig.Data); // ditto
+ return irtn;
+}
+
+static int rt_digest(opParams *op)
+{
+ int irtn;
+ CSSM_DATA ptext;
+ CSSM_DATA digest = {0, NULL};
+ CSSM_RETURN crtn;
+ unsigned len;
+
+ if((op->plainFileName == NULL) || (op->sigFileName == NULL)) {
+ printf("***Need plainFileName and sigFileName to digest.\n");
+ return 1;
+ }
+ irtn = readFile(op->plainFileName, &ptext.Data, &len);
+ if(irtn) {
+ printf("***Error reading %s\n", op->plainFileName);
+ return irtn;
+ }
+ ptext.Length = len;
+ crtn = cspDigest(op->cspHand,
+ op->alg,
+ CSSM_FALSE, // mallocDigest - let CSP do it
+ &ptext,
+ &digest);
+ if(crtn) {
+ printError("cspDigest", crtn);
+ return 1;
+ }
+ irtn = writeFile(op->sigFileName, digest.Data, digest.Length);
+ if(irtn) {
+ printf("***Error writing %s\n", op->sigFileName);
+ }
+ else if(!op->quiet){
+ printf("...wrote %lu bytes to %s\n", digest.Length, op->sigFileName);
+ }
+ free(ptext.Data); // allocd by readFile
+ appFreeCssmData(&digest, CSSM_FALSE); // by CSP
+ return irtn;
+}
+
+static int rt_convertPubKey(opParams *op)
+{
+ CSSM_RETURN crtn;
+ int irtn;
+ CSSM_KEY pubKeyIn;
+ CSSM_KEY pubKeyOut;
+ CSSM_KEY refKey;
+ char fileName[KEY_FILE_NAME_MAX_LEN];
+
+ if((op->keyFileName == NULL) || (op->outKeyFileName == NULL)) {
+ printf("***I need input and output key file names for public key concersion.\n");
+ return 1;
+ }
+ irtn = rt_readKey(op->cspHand, op->keyFileName, CSSM_TRUE, op->alg,
+ op->pubKeyFormat, &pubKeyIn);
+ if(irtn) {
+ return irtn;
+ }
+ crtn = cspRawKeyToRef(op->cspHand, &pubKeyIn, &refKey);
+ if(crtn) {
+ printf("***Error on NULL unwrap of %s\n", op->keyFileName);
+ return -1;
+ }
+ crtn = nullWrapKey(op->cspHand, &refKey, op->outPubKeyFormat, &pubKeyOut);
+ if(crtn) {
+ printf("***Error on NULL wrap\n");
+ return 1;
+ }
+
+ /* write the blobs */
+ rtKeyFileName(op->outKeyFileName, CSSM_TRUE, fileName);
+ irtn = writeFile(fileName, pubKeyOut.KeyData.Data, pubKeyOut.KeyData.Length);
+ if(irtn) {
+ printf("***Error %d writing to %s\n", irtn, fileName);
+ return irtn;
+ }
+ if(!op->quiet) {
+ printf("...wrote %lu bytes to %s\n", pubKeyOut.KeyData.Length, fileName);
+ }
+ cspFreeKey(op->cspHand, &pubKeyOut);
+ free(pubKeyIn.KeyData.Data);
+ cspFreeKey(op->cspHand, &refKey);
+ return 0;
+}
+
+/* parse public key format character */
+static CSSM_KEYBLOB_FORMAT parsePubKeyFormat(char c, char **argv)
+{
+ switch(c) {
+ case '1':
+ return CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
+ case 'x':
+ return CSSM_KEYBLOB_RAW_FORMAT_X509;
+ case 'b':
+ return CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
+ case 'o':
+ return CSSM_KEYBLOB_RAW_FORMAT_OPENSSH;
+ case 'O':
+ return CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2;
+ case 'L':
+ /* This is the "parse a private+public key as public only" option */
+ return CSSM_KEYBLOB_RAW_FORMAT_OPENSSL;
+ default:
+ usage(argv);
+ }
+ /* not reached */
+ return -1;
+}
+
+int main(int argc, char **argv)
+{
+ int arg;
+ char *argp;
+ int rtn;
+ opParams op;
+
+ if(argc < 2) {
+ usage(argv);
+ }
+ memset(&op, 0, sizeof(opParams));
+ op.keySizeInBits = DEFAULT_KEY_SIZE_BITS;
+ op.alg = CSSM_ALGID_RSA;
+ op.swapKeyClass = CSSM_FALSE;
+ op.rawSign = CSSM_FALSE;
+ op.noPad = CSSM_FALSE;
+
+ for(arg=2; arg<argc; arg++) {
+ argp = argv[arg];
+ switch(argp[0]) {
+ case 'a':
+ if(argp[1] != '=') {
+ usage(argv);
+ }
+ switch(argp[2]) {
+ case 'r':
+ op.alg = CSSM_ALGID_RSA;
+ break;
+ case 'd':
+ op.alg = CSSM_ALGID_DSA;
+ break;
+ case 'e':
+ op.alg = CSSM_ALGID_ECDSA;
+ break;
+ default:
+ usage(argv);
+ }
+ break;
+ case 'z':
+ op.keySizeInBits = atoi(&argp[2]);
+ break;
+ case 'k':
+ op.keyFileName = &argp[2];
+ break;
+ case 'K':
+ op.outKeyFileName = &argp[2];
+ break;
+ case 'p':
+ op.plainFileName = &argp[2];
+ break;
+ case 'c':
+ op.cipherFileName = &argp[2];
+ break;
+ case 's':
+ op.sigFileName = &argp[2];
+ break;
+ case 'w':
+ op.swapKeyClass = CSSM_TRUE;
+ break;
+ case 'r':
+ op.rawSign = CSSM_TRUE;
+ break;
+ case 'P':
+ op.noPad = CSSM_TRUE;
+ break;
+ case 'm':
+ op.dsaParamFileIn = &argp[2];
+ break;
+ case 'M':
+ op.dsaParamFileOut = &argp[2];
+ break;
+ case 'q':
+ op.quiet = CSSM_TRUE;
+ break;
+ case 'b':
+ if(argp[1] != '=') {
+ usage(argv);
+ }
+ op.pubKeyFormat = parsePubKeyFormat(argp[2], argv);
+ break;
+ case 'B':
+ if(argp[1] != '=') {
+ usage(argv);
+ }
+ op.outPubKeyFormat = parsePubKeyFormat(argp[2], argv);
+ break;
+ case 'v':
+ if(argp[1] != '=') {
+ usage(argv);
+ }
+ switch(argp[2]) {
+ case '1':
+ op.privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
+ break;
+ case '8':
+ op.privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
+ break;
+ case 's':
+ op.privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_OPENSSH;
+ break;
+ case 'b':
+ op.pubKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
+ break;
+ #if OPENSSL_ENABLE
+ case 'o':
+ op.privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL;
+ break;
+ #endif
+ default:
+ usage(argv);
+ }
+ break;
+ case 'd':
+ if(argp[1] != '=') {
+ usage(argv);
+ }
+ switch(argp[2]) {
+ case 's':
+ op.digestAlg = CSSM_ALGID_SHA1;
+ break;
+ case '5':
+ op.digestAlg = CSSM_ALGID_MD5;
+ break;
+ default:
+ usage(argv);
+ }
+ break;
+ case 'h':
+ default:
+ usage(argv);
+ }
+ }
+ op.cspHand = cspDlDbStartup(CSSM_TRUE, NULL);
+ if(op.cspHand == 0) {
+ exit(1);
+ }
+
+ /* specify blob formats if user didn't */
+ if(op.pubKeyFormat == CSSM_KEYBLOB_RAW_FORMAT_NONE) {
+ switch(op.alg) {
+ case CSSM_ALGID_RSA:
+ op.pubKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
+ break;
+ case CSSM_ALGID_DSA:
+ case CSSM_ALGID_ECDSA:
+ op.pubKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_X509;
+ break;
+ default:
+ printf("BRRZAP!\n");
+ exit(1);
+ }
+ }
+ if(op.privKeyFormat == CSSM_KEYBLOB_RAW_FORMAT_NONE) {
+ switch(op.alg) {
+ case CSSM_ALGID_RSA:
+ op.privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
+ break;
+ case CSSM_ALGID_DSA:
+ op.privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
+ break;
+ case CSSM_ALGID_ECDSA:
+ op.privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL;
+ break;
+ default:
+ printf("BRRZAP!\n");
+ exit(1);
+ }
+ }
+ switch(argv[1][0]) {
+ case 'g':
+ rtn = rt_generate(&op);
+ break;
+ case 'e':
+ rtn = rt_encrypt(&op);
+ break;
+ case 'd':
+ rtn = rt_decrypt(&op);
+ break;
+ case 's':
+ rtn = rt_sign(&op);
+ break;
+ case 'v':
+ rtn = rt_verify(&op);
+ break;
+ case 'S':
+ op.alg = CSSM_ALGID_SHA1;
+ rtn = rt_digest(&op);
+ break;
+ case 'M':
+ op.alg = CSSM_ALGID_MD5;
+ rtn = rt_digest(&op);
+ break;
+ case 'C':
+ rtn = rt_convertPubKey(&op);
+ break;
+ default:
+ usage(argv);
+ exit(1); // fool the compiler
+ }
+ CSSM_ModuleDetach(op.cspHand);
+ return rtn;
+}