Skip to content

Commit

Permalink
softhsm2-util: support import certificate
Browse files Browse the repository at this point in the history
The softhsm2-util already support importing keys, why not also import
certificates?

Useful for test scripts that require both keys and certificates.

Add --import-type <type> parameter, depreciate the --aes parameter.

Currently supported only for openssl backend.

Signed-off-by: Alon Bar-Lev <[email protected]>
  • Loading branch information
alonbl committed Feb 22, 2021
1 parent 3593859 commit 547eaad
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 12 deletions.
15 changes: 15 additions & 0 deletions src/bin/util/softhsm2-util-botan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -833,4 +833,19 @@ void crypto_free_eddsa(eddsa_key_material_t* keyMat)
if (keyMat->bigA) free(keyMat->bigA);
free(keyMat);
}

// Import a key pair from given path
int crypto_import_certificate
(
CK_SESSION_HANDLE hSession,
char* filePath,
char* label,
char* objID,
size_t objIDLen
)
{
fprintf(stderr, "ERROR: Unsupported in botan.\n");
return 1;
}

#endif
81 changes: 81 additions & 0 deletions src/bin/util/softhsm2-util-ossl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -990,4 +990,85 @@ void crypto_free_eddsa(eddsa_key_material_t* keyMat)
free(keyMat);
}

// Import a key pair from given path
int crypto_import_certificate
(
CK_SESSION_HANDLE hSession,
char* filePath,
char* label,
char* objID,
size_t objIDLen
)
{
BIO* in = NULL;

if (!(in = BIO_new_file(filePath, "rb")))
{
fprintf(stderr, "ERROR: Could open the PKCS#8 file: %s\n", filePath);
return 1;
}

X509* x509 = PEM_read_bio_X509(in, NULL, NULL, NULL);
BIO_free(in);

if (!x509)
{
fprintf(stderr, "ERROR: Could not read the certificate file.\n");
return 1;
}

int blobSize = i2d_X509(x509, NULL);
CK_BYTE_PTR blob = (CK_BYTE_PTR)malloc(blobSize);
CK_BYTE_PTR p;
p = blob;
blobSize = i2d_X509(x509, &p);

int nameSize = i2d_X509_NAME(X509_get_subject_name(x509), NULL);
CK_BYTE_PTR name = (CK_BYTE_PTR)malloc(nameSize);
p = name;
nameSize = i2d_X509_NAME(X509_get_subject_name(x509), &p);

int issuerSize = i2d_X509_NAME(X509_get_issuer_name(x509), NULL);
CK_BYTE_PTR issuer = (CK_BYTE_PTR)malloc(issuerSize);
p = issuer;
issuerSize = i2d_X509_NAME(X509_get_issuer_name(x509), &p);

int serialSize = i2d_ASN1_INTEGER(X509_get_serialNumber(x509), NULL);
CK_BYTE_PTR serial = (CK_BYTE_PTR)malloc(serialSize);
p = serial;
serialSize = i2d_ASN1_INTEGER(X509_get_serialNumber(x509), &p);

CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
CK_CERTIFICATE_TYPE certType = CKC_X_509;
CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE;
CK_ATTRIBUTE certTemplate[] = {
{ CKA_CLASS, &certClass, sizeof(certClass) },
{ CKA_CERTIFICATE_TYPE, &certType, sizeof(certType) },
{ CKA_LABEL, label, strlen(label) },
{ CKA_ID, objID, objIDLen },
{ CKA_TOKEN, &ckToken, sizeof(ckToken) },
{ CKA_PRIVATE, &ckFalse, sizeof(ckTrue) },
{ CKA_VALUE, blob, (CK_ULONG)blobSize },
{ CKA_SUBJECT, name, (CK_ULONG)nameSize },
{ CKA_ISSUER, issuer, (CK_ULONG)issuerSize },
{ CKA_SERIAL_NUMBER, serial, (CK_ULONG)serialSize }
};

CK_OBJECT_HANDLE hCert;
CK_RV rv = p11->C_CreateObject(hSession, certTemplate, 10, &hCert);
free(issuer);
free(name);
free(blob);
X509_free(x509);
if (rv != CKR_OK)
{
fprintf(stderr, "ERROR: Could not save the certificate in the token.\n");
return 1;
}

printf("The certificate has been imported.\n");

return 0;
}

#endif
152 changes: 141 additions & 11 deletions src/bin/util/softhsm2-util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,18 @@ void usage()
printf(" WARNING: Any content in token will be erased.\n");
printf(" -h Shows this help screen.\n");
printf(" --help Shows this help screen.\n");
printf(" --import <path> Import a key pair from the given path.\n");
printf(" The file must be in PKCS#8-format.\n");
printf(" Use with --slot or --token or --serial, --file-pin,\n");
printf(" --label, --id, --no-public-key, and --pin.\n");
printf(" --import <path>\n");
printf(" Import an object from the given path.\n");
printf(" Use with --import-type, --slot or --token or --serial,\n");
printf(" --file-pin, --label, --id, --no-public-key, and --pin.\n");
printf(" --import-type <type>\n");
printf(" Import object type, may be one of:\n");
printf(" keypair [default]\n");
printf(" The file must be in PKCS#8 PEM format.\n");
printf(" aes\n");
printf(" The file must be in binary format.\n");
printf(" cert\n");
printf(" The file must be in X509 PEM format.\n");
printf(" --init-token Initialize the token at a given slot.\n");
printf(" Use with --slot or --token or --serial or --free,\n");
printf(" --label, --so-pin, and --pin.\n");
Expand All @@ -114,6 +122,7 @@ void usage()
printf(" --version Show version info.\n");
printf("Options:\n");
printf(" --aes Used to tell import to use file as is and import it as AES.\n");
printf(" Deprecated, use '--import-type aes'.\n");
printf(" --file-pin <PIN> Supply a PIN if the file is encrypted.\n");
printf(" --force Used to override a warning.\n");
printf(" --free Use the first free/uninitialized token.\n");
Expand All @@ -130,6 +139,13 @@ void usage()
printf(" --token <label> Will use the token with a matching token label.\n");
}

// Enumeration of import types
enum {
IMPORT_TYPE_KEYPAIR,
IMPORT_TYPE_AES,
IMPORT_TYPE_CERT
};

// Enumeration of the long options
enum {
OPT_DELETE_TOKEN = 0x100,
Expand All @@ -139,6 +155,7 @@ enum {
OPT_HELP,
OPT_ID,
OPT_IMPORT,
OPT_IMPORT_TYPE,
OPT_INIT_TOKEN,
OPT_LABEL,
OPT_MODULE,
Expand All @@ -162,6 +179,7 @@ static const struct option long_options[] = {
{ "help", 0, NULL, OPT_HELP },
{ "id", 1, NULL, OPT_ID },
{ "import", 1, NULL, OPT_IMPORT },
{ "import-type", 1, NULL, OPT_IMPORT_TYPE },
{ "init-token", 0, NULL, OPT_INIT_TOKEN },
{ "label", 1, NULL, OPT_LABEL },
{ "module", 1, NULL, OPT_MODULE },
Expand Down Expand Up @@ -199,7 +217,7 @@ int main(int argc, char* argv[])
int forceExec = 0;
bool freeToken = false;
int noPublicKey = 0;
bool importAES = false;
int importType = IMPORT_TYPE_KEYPAIR;

int doInitToken = 0;
int doShowSlots = 0;
Expand Down Expand Up @@ -233,8 +251,20 @@ int main(int argc, char* argv[])
inPath = optarg;
needP11 = true;
break;
case OPT_IMPORT_TYPE:
if (!strcmp(optarg, "keypair"))
importType = IMPORT_TYPE_KEYPAIR;
else if (!strcmp(optarg, "aes"))
importType = IMPORT_TYPE_AES;
else if (!strcmp(optarg, "cert"))
importType = IMPORT_TYPE_CERT;
else
{
fprintf(stderr, "ERROR: Invalid import type '%s'\n", optarg);
}
break;
case OPT_AES:
importAES = true;
importType = IMPORT_TYPE_AES;
break;
case OPT_DELETE_TOKEN:
doDeleteToken = 1;
Expand Down Expand Up @@ -352,8 +382,17 @@ int main(int argc, char* argv[])
rv = findSlot(slot, serial, token, slotID);
if (!rv)
{
rv = importAES ? importSecretKey(inPath, slotID, userPIN, label, objectID)
: importKeyPair(inPath, filePIN, slotID, userPIN, label, objectID, forceExec, noPublicKey);
switch(importType)
{
case IMPORT_TYPE_KEYPAIR:
rv = importKeyPair(inPath, filePIN, slotID, userPIN, label, objectID, forceExec, noPublicKey);
break;
case IMPORT_TYPE_AES:
rv = importSecretKey(inPath, slotID, userPIN, label, objectID);
break;
case IMPORT_TYPE_CERT:
rv = importCertificate(inPath, slotID, userPIN, label, objectID, forceExec);
}
}
}

Expand Down Expand Up @@ -1099,7 +1138,7 @@ int importKeyPair
return 1;
}

CK_OBJECT_HANDLE oHandle = searchObject(hSession, objID, objIDLen);
CK_OBJECT_HANDLE oHandle = searchObject(hSession, CKO_PRIVATE_KEY, objID, objIDLen);
if (oHandle != CK_INVALID_HANDLE && forceExec == 0)
{
free(objID);
Expand Down Expand Up @@ -1187,6 +1226,98 @@ int importSecretKey(char* filePath, CK_SLOT_ID slotID, char* userPIN, char* labe
return result;
}

// Import a certificate from given path
int importCertificate
(
char* filePath,
CK_SLOT_ID slotID,
char* userPIN,
char* label,
char* objectID,
int forceExec
)
{
char user_pin_copy[MAX_PIN_LEN+1];

if (label == NULL)
{
fprintf(stderr, "ERROR: A label for the object must be supplied. "
"Use --label <text>\n");
return 1;
}

if (objectID == NULL)
{
fprintf(stderr, "ERROR: An ID for the object must be supplied. "
"Use --id <hex>\n");
return 1;
}

size_t objIDLen = 0;
char* objID = hexStrToBin(objectID, strlen(objectID), &objIDLen);
if (objID == NULL)
{
fprintf(stderr, "Please edit --id <hex> to correct error.\n");
return 1;
}

CK_SESSION_HANDLE hSession;
CK_RV rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION,
NULL_PTR, NULL_PTR, &hSession);
if (rv != CKR_OK)
{
if (rv == CKR_SLOT_ID_INVALID)
{
fprintf(stderr, "ERROR: The given slot does not exist.\n");
}
else
{
fprintf(stderr, "ERROR: Could not open a session on the given slot.\n");
}
free(objID);
return 1;
}

// Get the password
if (getPW(userPIN, user_pin_copy, CKU_USER) != 0)
{
fprintf(stderr, "ERROR: Could not get user PIN\n");
free(objID);
return 1;
}

rv = p11->C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy));
if (rv != CKR_OK)
{
if (rv == CKR_PIN_INCORRECT) {
fprintf(stderr, "ERROR: The given user PIN does not match the one in the token.\n");
}
else
{
fprintf(stderr, "ERROR: Could not log in on the token.\n");
}
free(objID);
return 1;
}

CK_OBJECT_HANDLE oHandle = searchObject(hSession, CKO_CERTIFICATE, objID, objIDLen);
if (oHandle != CK_INVALID_HANDLE && forceExec == 0)
{
free(objID);
fprintf(stderr, "ERROR: The ID is already assigned to another object. "
"Use --force to override this message.\n");
return 1;
}

crypto_init();
int result = crypto_import_certificate(hSession, filePath, label, objID, objIDLen);
crypto_final();

free(objID);

return result;
}

// Convert a char array of hexadecimal characters into a binary representation
char* hexStrToBin(char* objectID, int idLength, size_t* newLen)
{
Expand Down Expand Up @@ -1273,14 +1404,13 @@ int hexdigit_to_int(char ch)
}

// Search for an object
CK_OBJECT_HANDLE searchObject(CK_SESSION_HANDLE hSession, char* objID, size_t objIDLen)
CK_OBJECT_HANDLE searchObject(CK_SESSION_HANDLE hSession, CK_OBJECT_CLASS oClass, char* objID, size_t objIDLen)
{
if (objID == NULL)
{
return CK_INVALID_HANDLE;
}

CK_OBJECT_CLASS oClass = CKO_PRIVATE_KEY;
CK_OBJECT_HANDLE hObject = CK_INVALID_HANDLE;
CK_ULONG objectCount = 0;

Expand Down
4 changes: 3 additions & 1 deletion src/bin/util/softhsm2-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ bool rm(std::string path);
int showSlots();
int importKeyPair(char* filePath, char* filePIN, CK_SLOT_ID slotID, char* userPIN, char* objectLabel, char* objectID, int forceExec, int noPublicKey);
int importSecretKey(char* filePath, CK_SLOT_ID slotID, char* userPIN, char* label, char* objectID);
int importCertificate(char* filePath, CK_SLOT_ID slotID, char* userPIN, char* objectLabel, char* objectID, int forceExec);
int crypto_import_key_pair(CK_SESSION_HANDLE hSession, char* filePath, char* filePIN, char* label, char* objID, size_t objIDLen, int noPublicKey);
int crypto_import_aes_key(CK_SESSION_HANDLE hSession, char* filePath, char* label, char* objID, size_t objIDLen);
int crypto_import_certificate(CK_SESSION_HANDLE hSession, char* filePath, char* label, char* objID, size_t objIDLen);

// Support functions

Expand All @@ -72,6 +74,6 @@ static void* moduleHandle;
extern CK_FUNCTION_LIST_PTR p11;

/// PKCS#11 support
CK_OBJECT_HANDLE searchObject(CK_SESSION_HANDLE hSession, char* objID, size_t objIDLen);
CK_OBJECT_HANDLE searchObject(CK_SESSION_HANDLE hSession, CK_OBJECT_CLASS oClass, char* objID, size_t objIDLen);

#endif // !_SOFTHSM_V2_SOFTHSM2_UTIL_H

0 comments on commit 547eaad

Please sign in to comment.