| RSA BSAFE Cert-C |
Certificate Components for C |
| Crypto-C 6.2.1 Developer's Guide | ||
| Search |
/* $Id: sslcpvt.c,v 1.3 2004/03/02 05:18:32 gsingh Exp $ */
/* sslcpvt.c
** Copyright (c) 2001-2002, 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.
**
** Crypto-C and Cert-C use RSA private keys contained in PKCS #8
** PrivateKeyInfo containers, while SSL-C uses data in the raw PKCS #1
** RSAPrivateKey format. (The advantage of the PKCS #8 format, like the
** X.509 SubjectPublicKeyInfo for public keys, is that it contains an
** algorithm identifier specifying the type of key, so that an application
** receiving the key knows what type of key it is) This sample demonstrates
** the ASN.1 decoding APIs in Cert-C by taking a PKCS #8 binary, verifying
** that it is a PKCS #8 containing an RSAPrivateKey, extracting the
** RSAPrivateKey, and saving it to a file. Note that this is a binary,
** unencrypted RSA private key.
**
** Here is the ASN.1 definition of a PrivateKeyInfo:
**
** PrivateKeyInfo ::= SEQUENCE {
** version Version,
** privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
** privateKey PrivateKey,
** attributes [0] IMPLICIT Attributes OPTIONAL
** }
**
** PrivateKey ::= OCTET STRING
**
** Basically, we need to get the third item in the sequence and extract the
** value of that octet string.
**
** 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 "keyutil.h"
/* This routine prompts the user to supply a PKCS #8 PrivateKeyInfo and
* extracts the private key binary contained in it.
*/
static int ExtractKey (CERTC_CTX ctx);
/* This routine prompts the user to supply a PKCS #1 RSAPrivateKey and
* wraps it in a PKCS #8 PrivateKeyInfo. This example can be extended
* to encapsulate other keys.
*/
static int AssemblePrivateKeyInfo (CERTC_CTX ctx);
int main (int argc, char *argv[])
{
int status;
char command[RSA_DEMO_MAX_LINE_LEN];
CERTC_CTX ctx = NULL;
FILE_LOG_PARAMS logParams = {NULL, NULL};
SERVICE_HANDLER logHandler = {
SPT_LOG, "Default File Log", S_InitializeFileLog
};
status = RSA_SetOptions (&logParams, argc, argv);
if (status != 0)
goto CLEANUP;
status = C_InitializeCertC (NULL, NULL, 0, &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 ("Private Key Format Converter\n");
RSA_PrintMessage ("============================\n");
for (;;) {
RSA_PrintMessage ("\nPrivate Key Conversion Operations\n");
RSA_PrintMessage (" A - Extract key from PrivateKeyInfo\n");
RSA_PrintMessage (" B - Put key binary into PrivateKeyInfo\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 = ExtractKey (ctx);
break;
case 'b':
case 'B':
status = AssemblePrivateKeyInfo (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 ("asn1.c", status);
C_FinalizeCertC (&ctx);
return status;
} /* end main */
static int ExtractKey (CERTC_CTX ctx)
{
int status;
B_KEY_OBJ privateKey = NULL;
ITEM privateKeyInfoBer = {NULL, 0}, pvtBer = {NULL, 0};
ITEM *privateKeyBer = NULL;
int tag = 0;
unsigned int tagClass = 0;
LIST_OBJ privateKeyInfoItems = NULL;
RSA_PrintMessage ("\nPlease supply a PKCS #8 PrivateKeyInfo binary.\n");
status = RSA_GetKeyObjFromFile (RSA_DEMO_PRIVATE_KEY, &privateKey);
if (status != 0)
goto CLEANUP;
status = RSA_GetKeyBer (RSA_DEMO_PRIVATE_KEY, privateKey,
&privateKeyInfoBer);
if (status != 0)
goto CLEANUP;
/* Pull apart the PrivateKeyInfo SEQUENCE */
status = C_CreateListObject (&privateKeyInfoItems);
if (status != 0)
goto CLEANUP;
status = C_BERDecodeList (ctx, privateKeyInfoBer.data, privateKeyInfoBer.len,
&tag, &tagClass, privateKeyInfoItems);
if (status != 0)
goto CLEANUP;
if (tag != VT_SEQUENCE) {
status = RSA_DEMO_E_INVALID_MESSAGE;
RSA_PrintMessage ("Expected VT_SEQUENCE...\n");
goto CLEANUP;
}
/* If desired, the second element in the PrivateKeyInfo can be examined
* to see if it is a known algorithm identifier to identify the type of
* key we are going to extract. We leave this as an optional exercise
* for the reader.
*/
/* Access the PrivateKey, the third element in the PrivateKeyInfo */
status = C_GetListObjectEntry (privateKeyInfoItems, 2,
(POINTER *)&privateKeyBer);
if (status != 0)
goto CLEANUP;
/* The privateKeyBer should be an OCTET STRING */
status = C_BERDecodeString (ctx, privateKeyBer->data, privateKeyBer->len,
&tag, &tagClass, &pvtBer.data, &pvtBer.len);
if (status != 0)
goto CLEANUP;
if (tag != VT_OCTET_STRING) {
status = RSA_DEMO_E_INVALID_MESSAGE;
RSA_PrintMessage ("Expected VT_OCTET_STRING...\n");
goto CLEANUP;
}
status = RSA_WriteDataToFile (pvtBer.data, pvtBer.len,
"Enter name of file to store extracted private key binary");
CLEANUP:
if (status != 0)
RSA_PrintError ("ExtractKey", status);
T_memset (pvtBer.data, 0, pvtBer.len);
T_free (pvtBer.data);
T_memset (privateKeyInfoBer.data, 0, privateKeyInfoBer.len);
T_free (privateKeyInfoBer.data);
B_DestroyKeyObject (&privateKey);
C_DestroyListObject (&privateKeyInfoItems);
return status;
} /* end ExtractKey */
static int AssemblePrivateKeyInfo (CERTC_CTX ctx)
{
int status;
ITEM rsaPvtKeyBer = {NULL, 0}, pvtKeyOctetString = {NULL, 0};
ITEM pvtKeyInfoBer = {NULL, 0};
LIST_OBJ sequence = NULL;
unsigned char pkcs8Version[] = {
0x02, 0x01, 0x00
};
unsigned char rsaEncryptionAlgId[] = {
0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00
};
ITEM version, algId;
RSA_PrintMessage ("\nThis example currently assumes that you want to wrap ");
RSA_PrintMessage ("a\nPKCS #1 RSAPrivateKey in a PKCS #8 PrivateKeyInfo.");
RSA_PrintMessage (" No\nchecking is done on the PKCS #1 binary you ");
RSA_PrintMessage ("supply.\n\n");
status = RSA_GetFileToAllocBuffer
(&rsaPvtKeyBer.data, &rsaPvtKeyBer.len,
"Enter name of file containing a binary PKCS #1 RSAPrivateKey");
if (status != 0)
goto CLEANUP;
/* Wrap the private key in an OCTET STRING */
status = C_DEREncodeString (ctx, VT_OCTET_STRING, VTC_UNIVERSAL,
rsaPvtKeyBer.data, rsaPvtKeyBer.len,
&pvtKeyOctetString.data, &pvtKeyOctetString.len);
if (status != 0)
goto CLEANUP;
/* Create the PKCS #8 PrivateKeyInfo SEQUENCE containing the version,
* RSA Enryption algorithm identifier, and the private key OCTET STRING.
* This program only handles RSA keys; checking and supporting algorithm
* identifiers for other types of keys is left as an exercise for the user.
*/
status = C_CreateListObject (&sequence);
if (status != 0)
goto CLEANUP;
version.data = pkcs8Version;
version.len = sizeof (pkcs8Version);
status = C_AddItemToList (sequence, &version, NULL);
if (status != 0)
goto CLEANUP;
algId.data = rsaEncryptionAlgId;
algId.len = sizeof (rsaEncryptionAlgId);
status = C_AddItemToList (sequence, &algId, NULL);
if (status != 0)
goto CLEANUP;
status = C_AddItemToList (sequence, &pvtKeyOctetString, NULL);
if (status != 0)
goto CLEANUP;
status = C_DEREncodeList (ctx, VT_SEQUENCE, VTC_UNIVERSAL, sequence,
&pvtKeyInfoBer.data, &pvtKeyInfoBer.len);
if (status != 0)
goto CLEANUP;
status = RSA_WriteDataToFile
(pvtKeyInfoBer.data, pvtKeyInfoBer.len,
"Enter name of file to store PKCS #8 PrivateKeyInfo binary");
CLEANUP:
if (status != 0)
RSA_PrintError ("AssemblePrivateKeyInfo", status);
T_memset (rsaPvtKeyBer.data, 0, rsaPvtKeyBer.len);
T_free (rsaPvtKeyBer.data);
T_memset (pvtKeyOctetString.data, 0, pvtKeyOctetString.len);
T_free (pvtKeyOctetString.data);
T_memset (pvtKeyInfoBer.data, 0, pvtKeyInfoBer.len);
T_free (pvtKeyInfoBer.data);
C_DestroyListObject (&sequence);
return status;
} /* end AssemblePrivateKeyInfo */