| RSA BSAFE Cert-C |
Certificate Components for C |
| Crypto-C 6.2.1 Developer's Guide | ||
| Search |
/* $Id: pkcs10.c,v 1.6 2004/04/15 02:40:38 itaylor Exp $ */ /* pkcs10.c ** Copyright (c) 1999-2003, RSA Security Inc. ** ** This file is used to demonstrate how to interface to an RSA Security ** licensed development product. You have a royalty-free right to use, ** modify, reproduce and distribute this demonstration file (including ** any modified version), provided that you agree that RSA Security has ** no warranty, implied or otherwise, or liability for this demonstration ** file or any modified version. ** ** Demonstrate how to parse or generate certificate requests. ** ** When compiling, define the macro RSA_REQUIRE_FILE_LOG (-D compile ** option, or equivelent) to force the program to return an error code ** if file logging cannot be initialized. For example, if the file ** containing the log message format strings cannot be located (certc.msg ** or equivalent). */ #include "certc.h" #include "filelog.h" #include "demoutil.h" #include "p10util.h" #include "certutil.h" #include "rsacsp.h" #include "filelog.h" #include "attributil.h" /* The number of service providers used in this example. Here, we must * register a crypto service provider. */ #define SP_COUNT 1 static int DisplayPkcs10Obj (CERTC_CTX ctx); static int GeneratePkcs10Obj (CERTC_CTX ctx); static int VerifyPkcs10Signature (CERTC_CTX ctx); static int ExtractObjsFromPkcs10 (CERTC_CTX ctx); static int VerifyPkcs10Signature2 (CERTC_CTX ctx); static int CryptoCVerifySignature (ITEM *dataToSign, ITEM *signature, ITEM *signatureAlgId, B_KEY_OBJ publicKey); static int PKCS10ObjToCertObj (CERTC_CTX ctx); int main (int argc, char *argv[]) { int status = 0; char command[RSA_DEMO_MAX_LINE_LEN]; CERTC_CTX ctx = NULL; SERVICE_HANDLER spTable[SP_COUNT]; POINTER spParams[SP_COUNT]; FILE_LOG_PARAMS logParams = {NULL, NULL}; SERVICE_HANDLER logHandler = { SPT_LOG, "Default File Log", S_InitializeFileLog }; spTable[0].type = SPT_CRYPTO; spTable[0].name = "BSAFE Crypto-C"; spTable[0].Initialize = S_InitializeDefaultCSP; spParams[0] = NULL; status = RSA_SetOptions (&logParams, argc, argv); if (status != 0) goto CLEANUP; status = C_InitializeCertC (spTable, spParams, SP_COUNT, &ctx); if (status != 0) goto CLEANUP; /* Attempt to initialize file logging, but unless RSA_REQUIRE_FILE_LOG is * defined, treat it as a non-fatal condition. */ status = C_RegisterService (ctx, &logHandler, (POINTER)&logParams, SERVICE_ORDER_FIRST); #ifdef RSA_REQUIRE_FILE_LOG if (status != 0) goto CLEANUP; #endif RSA_PrintMessage ("PKCS #10 Cert Request Object Demonstration\n"); RSA_PrintMessage ("==========================================\n"); for (;;) { RSA_PrintMessage ("\nPKCS #10 Object Operations\n"); RSA_PrintMessage (" A - Display PKCS #10 object from a file\n"); RSA_PrintMessage (" B - Generate PKCS #10 object\n"); RSA_PrintMessage (" C - Verify PKCS #10 signature\n"); RSA_PrintMessage (" D - Extract objects from PKCS #10\n"); RSA_PrintMessage (" E - Verify PKCS #10 signature (alternate method)\n"); RSA_PrintMessage (" F - Convert PKCS #10 to X.509 Cert\n"); status = RSA_GetCommand (command, sizeof (command), "Enter choice (blank to quit)"); if (status != 0) goto CLEANUP; switch (command[0]) { case 'a': case 'A': status = DisplayPkcs10Obj (ctx); break; case 'b': case 'B': status = GeneratePkcs10Obj (ctx); break; case 'c': case 'C': status = VerifyPkcs10Signature (ctx); break; case'd': case'D': status = ExtractObjsFromPkcs10 (ctx); break; case 'e': case 'E': status = VerifyPkcs10Signature2 (ctx); break; case 'f': case 'F': status = PKCS10ObjToCertObj (ctx); break; case '\0': case 'q': case 'Q': goto CLEANUP; default: RSA_PrintMessage ("Unrecognized Option: %c\n", command[0]); status = RSA_DEMO_E_INVALID_PARAMETER; } if (status != 0) RSA_PrintMessage ("Operation not completed.\n"); else RSA_PrintMessage ("Operation successful!\n"); } CLEANUP: if (status != 0) RSA_PrintError ("pkcs10.c", status); C_FinalizeCertC (&ctx); return status; } /* end main */ static int DisplayPkcs10Obj (CERTC_CTX ctx) { int status = 0; unsigned char *pkcs10Ber = NULL; unsigned int pkcs10BerLen = 0; PKCS10_OBJ pkcs10Obj = NULL; status = RSA_GetFileToAllocBuffer (&pkcs10Ber, &pkcs10BerLen, "Enter name of PKCS #10 object binary"); if (status != 0) goto CLEANUP; status = C_CreatePKCS10Object (ctx, &pkcs10Obj); if (status != 0) goto CLEANUP; status = C_SetPKCS10BER (pkcs10Obj, pkcs10Ber, pkcs10BerLen); if (status != 0) goto CLEANUP; RSA_PrintMessage ("\nPKCS #10 Object Contents\n"); status = RSA_PrintPkcs10Object (pkcs10Obj); if (status != 0) goto CLEANUP; CLEANUP: if (status != 0) RSA_PrintError ("DisplayPkcs10Obj", status); C_DestroyPKCS10Object (&pkcs10Obj); T_free (pkcs10Ber); return status; } /* end DisplayPkcs10Obj */ static int GeneratePkcs10Obj (CERTC_CTX ctx) { int status = 0; PKCS10_OBJ pkcs10Obj = NULL; unsigned char *pkcs10Ber = NULL; unsigned int pkcs10BerLen = 0; status = C_CreatePKCS10Object (ctx, &pkcs10Obj); if (status != 0) goto CLEANUP; status = RSA_GetInputToPkcs10Object (pkcs10Obj, ctx); if (status != 0) goto CLEANUP; status = C_GetPKCS10DER (pkcs10Obj, &pkcs10Ber, &pkcs10BerLen); if (status != 0) goto CLEANUP; status = RSA_WriteDataToFile (pkcs10Ber, pkcs10BerLen, "Enter file name to store PKCS #10 object binary"); if (status != 0) goto CLEANUP; CLEANUP: if (status != 0) RSA_PrintError ("GeneratePkcs10Obj", status); C_DestroyPKCS10Object (&pkcs10Obj); return status; } /* end GeneratePkcs10Obj */ static int VerifyPkcs10Signature (CERTC_CTX ctx) { int status = 0; unsigned char *pkcs10Ber = NULL_PTR; unsigned int pkcs10BerLen = 0; PKCS10_OBJ pkcs10Obj = NULL; status = RSA_GetFileToAllocBuffer (&pkcs10Ber, &pkcs10BerLen, "Enter name of PKCS #10 object binary"); if (status != 0) goto CLEANUP; status = C_CreatePKCS10Object (ctx, &pkcs10Obj); if (status != 0) goto CLEANUP; status = C_SetPKCS10BER (pkcs10Obj, pkcs10Ber, pkcs10BerLen); if (status != 0) goto CLEANUP; status = C_VerifyPKCS10Signature (pkcs10Obj); if (status != 0) goto CLEANUP; RSA_PrintMessage ("PKCS #10 signature verified successfully!\n"); CLEANUP: if (status != 0) RSA_PrintError ("VerifyPkcs10Signature", status); T_free (pkcs10Ber); C_DestroyPKCS10Object (&pkcs10Obj); return status; } /* end VerifyPkcs10Signature */ static int ExtractObjsFromPkcs10 (CERTC_CTX ctx) { int status = 0; unsigned char *pkcs10Ber = NULL_PTR; unsigned int pkcs10BerLen = 0; PKCS10_OBJ pkcs10Obj = NULL; PKCS10_FIELDS pkcs10Fields; char *nameString = NULL; ITEM nameDer = {NULL, 0}, attributesDer = {NULL, 0}; status = RSA_GetFileToAllocBuffer (&pkcs10Ber, &pkcs10BerLen, "Enter name of PKCS #10 object binary"); if (status != 0) goto CLEANUP; status = C_CreatePKCS10Object (ctx, &pkcs10Obj); if (status != 0) goto CLEANUP; status = C_SetPKCS10BER (pkcs10Obj, pkcs10Ber, pkcs10BerLen); if (status != 0) goto CLEANUP; status = C_GetPKCS10Fields (pkcs10Obj, &pkcs10Fields); if (status != 0) goto CLEANUP; status = C_GetNameStringReverse (pkcs10Fields.subjectName, &nameString); if (status != 0) goto CLEANUP; RSA_PrintMessage ("Subject Name: %s\n", nameString); status = C_GetNameDER (pkcs10Fields.subjectName, &nameDer.data, &nameDer.len); if (status != 0) goto CLEANUP; status = RSA_WriteDataToFile (nameDer.data, nameDer.len, "Enter name of file to store subject name binary"); if (status != 0) goto CLEANUP; status = RSA_WriteDataToFile (pkcs10Fields.publicKey.data, pkcs10Fields.publicKey.len, "Enter name of file to store public key binary"); if (status != 0) goto CLEANUP; if (pkcs10Fields.attribute != NULL) { status = C_GetAttributesDER (pkcs10Fields.attribute, &attributesDer.data, &attributesDer.len); if (status != 0) goto CLEANUP; status = RSA_WriteDataToFile (attributesDer.data, attributesDer.len, "Enter name of file to store attributes object binary"); if (status != 0) goto CLEANUP; } CLEANUP: if (status != 0) RSA_PrintError ("ExtractObjsFromPkcs10", status); C_DestroyPKCS10Object (&pkcs10Obj); return status; } /* end ExtractObjsFromPkcs10 */ /* This is an example demonstrating how to use the ASN.1 APIs to pull apart * a PKCS 10 request and verify the signature. */ static int VerifyPkcs10Signature2 (CERTC_CTX ctx) { int status = 0; unsigned char *pkcs10Ber = NULL_PTR; unsigned int pkcs10BerLen = 0; PKCS10_OBJ pkcs10Obj = NULL; LIST_OBJ contents = NULL; int tag; unsigned int tagClass, count; ITEM *dataToSign = NULL, *signatureAlgId = NULL, *bitString = NULL; ITEM signatureItem = {NULL, 0}; BIT_STRING signature = {NULL, 0, 0}; B_KEY_OBJ publicKey = NULL; status = RSA_GetFileToAllocBuffer (&pkcs10Ber, &pkcs10BerLen, "Enter name of PKCS #10 object binary"); if (status != 0) goto CLEANUP; status = C_CreatePKCS10Object (ctx, &pkcs10Obj); if (status != 0) goto CLEANUP; status = C_SetPKCS10BER (pkcs10Obj, pkcs10Ber, pkcs10BerLen); if (status != 0) goto CLEANUP; status = C_CreateListObject (&contents); if (status != 0) goto CLEANUP; /* We want to get the portion of the PKCS #10 that was signed, the signature algorithm ID, and the signature. We will then use this information with Crypto-C calls to verify the signature. */ status = C_BERDecodeList (ctx, pkcs10Ber, pkcs10BerLen, &tag, &tagClass, contents); if (status != 0) goto CLEANUP; /* The PKCS #10 Certification Request is supposed to be a SEQUENCE */ if (tag != VT_SEQUENCE) { status = RSA_DEMO_E_INVALID_TAG; goto CLEANUP; } status = C_GetListObjectCount (contents, &count); if (status != 0) goto CLEANUP; if (count != 3) { status = RSA_DEMO_E_INVALID_MESSAGE; goto CLEANUP; } status = C_GetListObjectEntry (contents, 0, (POINTER *)&dataToSign); if (status != 0) goto CLEANUP; status = C_GetListObjectEntry (contents, 1, (POINTER *)&signatureAlgId); if (status != 0) goto CLEANUP; status = C_GetListObjectEntry (contents, 2, (POINTER *)&bitString); if (status != 0) goto CLEANUP; status = C_BERDecodeBitString (ctx, bitString->data, bitString->len, &tag, &tagClass, &signature); if (status != 0) goto CLEANUP; if (tag != VT_BIT_STRING) { status = RSA_DEMO_E_INVALID_TAG; goto CLEANUP; } /* Handle the case where unused bits is 0. */ if (signature.unusedBits != 0) { status = RSA_DEMO_E_NOT_IMPLEMENTED; goto CLEANUP; } signatureItem.data = signature.data; signatureItem.len = signature.len; status = RSA_GetKeyFromPkcs10 (pkcs10Obj, &publicKey); if (status != 0) goto CLEANUP; status = CryptoCVerifySignature (dataToSign, &signatureItem, signatureAlgId, publicKey); CLEANUP: if (status != 0) RSA_PrintError ("VerifyPkcs10Signature2", status); B_DestroyKeyObject (&publicKey); C_DestroyListObject (&contents); C_DestroyPKCS10Object (&pkcs10Obj); return status; } /* end VerifyPkcs10Signature2 */ static int CryptoCVerifySignature (ITEM *dataToSign, ITEM *signature, ITEM *signatureAlgId, B_KEY_OBJ publicKey) { int status = 0, i; B_ALGORITHM_OBJ verifyObj = NULL; B_INFO_TYPE algorithmInfos[] = { AI_MD2WithRSAEncryptionBER, AI_MD5WithRSAEncryptionBER, AI_SHA1WithRSAEncryptionBER, AI_DSAWithSHA1_BER }; B_ALGORITHM_METHOD *chooser[] = { &AM_MD2, &AM_MD5, &AM_SHA, &AM_RSA_DECRYPT, &AM_DSA_VERIFY, NULL }; unsigned char x957DsaWithSha1Oid[] = { 0x30, 0x09, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x38, 0x04, 0x03 }; status = B_CreateAlgorithmObject (&verifyObj); if (status != 0) goto CLEANUP; for (i = 0; i < sizeof (algorithmInfos) / sizeof (algorithmInfos[0]); i++) { status = B_SetAlgorithmInfo (verifyObj, algorithmInfos[i], (POINTER)signatureAlgId); if (status == 0) break; } /* Check the X9.57 DSA with SHA1 OID, since AI_DSAWithSHA1_BER doesn't accept it. (Crypto-C bug #13474) */ if (signatureAlgId->len == sizeof (x957DsaWithSha1Oid) && T_memcmp (signatureAlgId->data, x957DsaWithSha1Oid, sizeof (x957DsaWithSha1Oid)) == 0) status = B_SetAlgorithmInfo (verifyObj, AI_DSAWithSHA1, NULL); /* if none of the AIs in algorithmInfos worked, return an error code */ if (status != 0) goto CLEANUP; status = B_VerifyInit (verifyObj, publicKey, chooser, NULL); if (status != 0) goto CLEANUP; status = B_VerifyUpdate (verifyObj, dataToSign->data, dataToSign->len, NULL); if (status != 0) goto CLEANUP; status = B_VerifyFinal (verifyObj, signature->data, signature->len, NULL, NULL); CLEANUP: if (status != 0) RSA_PrintError ("CryptoCVerifyPkcs10Signature2", status); B_DestroyAlgorithmObject (&verifyObj); return status; } /* end CryptoCVerifySignature */ static int PKCS10ObjToCertObj (CERTC_CTX ctx) { int status; unsigned char *pkcs10Ber = NULL; unsigned int pkcs10BerLen = 0; PKCS10_OBJ pkcs10Obj = NULL; PKCS10_FIELDS pkcs10Fields = {0}; CERT_OBJ newCert = NULL; CERT_FIELDS newCertFields = {0}; CERT_OBJ issuerCert = NULL; CERT_FIELDS issuerCertFields = {0}; B_KEY_OBJ privateKey = NULL; ITEM issuerCertBer = {0}, privateKeyBer = {0}; ALGORITHM_IDENTIFIER signatureAlg = {0}; ITEM subjectNameBer, issuerNameBer; EXTENSIONS_OBJ certExt = NULL; ITEM certExtBer = {0}; status = RSA_GetFileToAllocBuffer (&pkcs10Ber, &pkcs10BerLen, "Enter name of PKCS #10 object binary"); if (status != 0) goto CLEANUP; status = C_CreatePKCS10Object (ctx, &pkcs10Obj); if (status != 0) goto CLEANUP; status = C_SetPKCS10BER (pkcs10Obj, pkcs10Ber, pkcs10BerLen); if (status != 0) goto CLEANUP; status = C_GetPKCS10Fields (pkcs10Obj, &pkcs10Fields); if (status != 0) goto CLEANUP; RSA_PrintMessage ("Creating new cert object...\n"); status = C_CreateCertObject (&newCert, ctx); if (status != 0) goto CLEANUP; /* initialize blank cert fields */ status = C_GetCertFields (newCert, &newCertFields); if (status != 0) goto CLEANUP; /* newCertFields.version defaults to 1 */ newCertFields.version = CERT_VERSION_1; status = RSA_GetItem (&newCertFields.serialNumber, "Enter hex-ascii serial number (blank to quit)"); if (status != 0) goto CLEANUP; status = RSA_ChooseSignatureAlgorithmPrompt (&signatureAlg); if (status != 0) goto CLEANUP; newCertFields.signatureAlgorithm = signatureAlg.algorithmId; status = RSA_GetInputToUint4Time (&newCertFields.validity.start, "Enter validity start"); if (status != 0) goto CLEANUP; status = RSA_GetInputToUint4Time (&newCertFields.validity.end, "Enter validity end"); if (status != 0) goto CLEANUP; /* Prompt user to supply issuer cert and private key. If none is supplied, this will be a self-signed cert */ RSA_PrintMessage ("Supply the signer's cert and private key, or enter "); RSA_PrintMessage ("a blank\nto self-sign the cert.\n"); status = RSA_GetFileToAllocBuffer (&issuerCertBer.data, &issuerCertBer.len, "Enter file containing issuer cert binary (blank to self-sign)"); if (status == 0) { /* setting issuerCert to non-NULL value means that we don't have a self-signed cert */ status = C_CreateCertObject (&issuerCert, ctx); if (status != 0) goto CLEANUP; status = C_SetCertBER (issuerCert, issuerCertBer.data, issuerCertBer.len); if (status != 0) goto CLEANUP; status = C_GetCertFields (issuerCert, &issuerCertFields); if (status != 0) goto CLEANUP; status = C_GetNameDER (issuerCertFields.issuerName, &issuerNameBer.data, &issuerNameBer.len); if (status != 0) goto CLEANUP; status = C_SetNameBER (newCertFields.issuerName, issuerNameBer.data, issuerNameBer.len); if (status != 0) goto CLEANUP; } else if (status != 0 && status != RSA_DEMO_E_CANCEL) goto CLEANUP; if (status == 0) RSA_PrintMessage ("Supply private key corresponding to issuer cert.\n"); else RSA_PrintMessage ("Supply private key for self-signing certificate.\n"); status = RSA_GetFileToAllocBuffer (&privateKeyBer.data, &privateKeyBer.len, "Enter file containing private key binary for signing cert"); if (status != 0) goto CLEANUP; status = B_CreateKeyObject (&privateKey); if (status != 0) goto CLEANUP; status = RSA_SetKeyBer (RSA_DEMO_PRIVATE_KEY, privateKey, privateKeyBer); if (status != 0) goto CLEANUP; /* copy name in PKCS #10 request to new cert */ status = C_GetNameDER (pkcs10Fields.subjectName, &subjectNameBer.data, &subjectNameBer.len); if (status != 0) goto CLEANUP; /* our blank cert fields contains an already-created name object */ status = C_SetNameBER (newCertFields.subjectName, subjectNameBer.data, subjectNameBer.len); if (status != 0) goto CLEANUP; /* if the user requests a self signed cert, issuerCert is NULL */ if (issuerCert == NULL) { status = C_SetNameBER (newCertFields.issuerName, subjectNameBer.data, subjectNameBer.len); if (status != 0) goto CLEANUP; } newCertFields.publicKey.data = pkcs10Fields.publicKey.data; newCertFields.publicKey.len = pkcs10Fields.publicKey.len; /* give option to "upgrade" to a v2 cert */ status = RSA_GetBitString (&newCertFields.issuerUniqueID, "Enter optional unique ID of cert issuer (blank to omit)"); if (status != 0 && status != RSA_DEMO_E_CANCEL) goto CLEANUP; else if (status == 0) newCertFields.version = CERT_VERSION_2; status = RSA_GetBitString (&newCertFields.subjectUniqueID, "Enter optional unique ID of cert subject (blank to omit)"); if (status != 0 && status != RSA_DEMO_E_CANCEL) goto CLEANUP; else if (status == 0) newCertFields.version = CERT_VERSION_2; /* give option to "upgrade" to a v3 cert */ status = C_CreateExtensionsObject (&certExt, CERT_EXTENSIONS_OBJ, ctx); if (status != 0) goto CLEANUP; status = C_GetExtensionsInAttributesObj (certExt, pkcs10Fields.attribute); if (status == 0) { RSA_PrintMessage ("Extracting extensions from PKCS #10...\n"); newCertFields.version = CERT_VERSION_3; status = C_GetExtensionsObjectDER (certExt, &certExtBer.data, &certExtBer.len); if (status != 0) goto CLEANUP; status = C_SetExtensionsObjectBER (newCertFields.certExtensions, certExtBer.data, certExtBer.len); if (status != 0) goto CLEANUP; } else if (status != 0) { /* optionally specify extensions */ status = RSA_GetFileToExtensionsObject (ctx, &newCertFields.certExtensions); if (status != 0 && status != RSA_DEMO_E_CANCEL) goto CLEANUP; if (status == 0) newCertFields.version = CERT_VERSION_3; } status = C_SetCertFields (newCert, &newCertFields); if (status != 0) goto CLEANUP; status = C_SignCert (newCert, privateKey); if (status != 0) goto CLEANUP; RSA_PrintMessage ("New Certificate:\n"); status = RSA_PrintCertObject (newCert); if (status != 0) goto CLEANUP; status = RSA_SaveCertObjToFile (newCert); CLEANUP: if (status != 0) RSA_PrintError ("PKCS10ObjToCertObj", status); T_memset (privateKeyBer.data, 0, privateKeyBer.len); T_free (privateKeyBer.data); T_free (newCertFields.serialNumber.data); T_free (issuerCertBer.data); B_DestroyKeyObject (&privateKey); C_DestroyCertObject (&issuerCert); C_DestroyCertObject (&newCert); return status; } /* end PKCS10ObjToCertObj */