📄 data_import.c
字号:
/* * The Initial Developer of the Original Code is International * Business Machines Corporation. Portions created by IBM * Corporation are Copyright (C) 2005 International Business * Machines Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the Common Public License as published by * IBM Corporation; either version 1 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * Common Public License for more details. * * You should have received a copy of the Common Public License * along with this program; if not, a copy can be viewed at * http://www.opensource.org/licenses/cpl1.0.php. */#include "data_import.h"#include "data_common.h"#include <tpm_pkcs11.h>#include <tpm_utils.h>#include <stdlib.h>#include <unistd.h>#define _GNU_SOURCE#include <getopt.h>#include <errno.h>#include <openssl/rsa.h>#include <openssl/x509.h>#include <openssl/x509v3.h>#include <openssl/pem.h>#include <openssl/asn1.h>#include <openssl/evp.h>#include <openssl/err.h>/* * Global variables */char *g_pszFile = NULL; // Object import file namechar *g_pszIdFile = NULL; // Object identification file namechar *g_pszType = NULL; // Object import typeint g_bPublic = FALSE; // Public object specifierint g_bYes = FALSE; // Yes/No prompt replychar *g_pszToken = NULL; // Token label to be usedint g_bAttrsValid = FALSE;CK_BYTE *g_pchSubject = NULL; // SUBJECT attribute valueCK_ULONG g_ulSubjectLen = 0;CK_BYTE *g_pchId = NULL; // ID attribute valueCK_ULONG g_ulIdLen = 0;CK_BYTE *g_pchName = NULL; // LABEL attribute valueCK_ULONG g_ulNameLen = 0;/* * parseCallback * Process the command specific options. */intparseCallback( int a_iOpt, const char *a_pszOptArg ) { switch ( a_iOpt ) { // File with object to be used to obtain subject/id case 'i': if ( !a_pszOptArg ) return -1; g_pszIdFile = strdup( a_pszOptArg ); break; // Use the specified token label when finding the token case 'k': if ( !a_pszOptArg ) return -1; g_pszToken = strdup( a_pszOptArg ); break; // Name to use as the LABEL attribute value case 'n': if ( !a_pszOptArg ) return -1; g_pchName = (CK_BYTE *)strdup( a_pszOptArg ); g_ulNameLen = strlen( a_pszOptArg ); break; // Make the object public case 'p': g_bPublic = TRUE; break; // Only import the specified object type case 't': if ( !a_pszOptArg ) return -1; if ( ( strcmp( a_pszOptArg, TOKEN_OBJECT_KEY ) != 0 ) && ( strcmp( a_pszOptArg, TOKEN_OBJECT_CERT ) != 0 ) ) return -1; g_pszType = strdup( a_pszOptArg ); break; // Reply "yes" to any yes/no prompts case 'y': g_bYes = TRUE; break; } return 0;}/* * usageCallback * Display command usage information. */voidusageCallback( const char *a_pszCmd ) { char *pszArgs[2]; char *pszArgsDesc[2]; pszArgs[ 0 ] = "FILE"; pszArgsDesc[ 0 ] = _("Import the PEM formatted RSA key and/or X.509 certificate object contained in FILE"); pszArgs[ 1 ] = NULL; pszArgsDesc[ 1 ] = NULL; logCmdHelpEx( a_pszCmd, pszArgs, pszArgsDesc ); logCmdOption( "-i, --idfile FILE", _("Use FILE as the PEM formatted X.509 certificate input used to obtain the subject and id attributes") ); logCmdOption( "-k, --token STRING", _("Use STRING to identify the label of the PKCS#11 token to be used") ); logCmdOption( "-n, --name STRING", _("Use STRING as the label for the imported object(s)") ); logCmdOption( "-p, --public", _("Import the object(s) as a public object") ); logCmdOption( "-t, --type key|cert", _("Import only the specified object type") ); logCmdOption( "-y, --yes", _("Assume yes as the answer to any confirmation prompt") );}/* * parseCmd * Parse the command line options. */intparseCmd( int a_iArgc, char **a_pszArgv ) { int rc; char *pszShortOpts = "i:k:n:pt:y"; struct option stLongOpts[] = { { "idfile", required_argument, NULL, 'i' }, { "name", required_argument, NULL, 'n' }, { "public", no_argument, NULL, 'p' }, { "token", required_argument, NULL, 'k' }, { "type", required_argument, NULL, 't' }, { "yes", no_argument, NULL, 'y' }, }; int iNumLongOpts = sizeof( stLongOpts ) / sizeof( struct option ); rc = genericOptHandler( a_iArgc, a_pszArgv, pszShortOpts, stLongOpts, iNumLongOpts, parseCallback, usageCallback ); if ( rc == -1 ) return -1; if ( optind >= a_iArgc ) { logMsg( TOKEN_FILE_ERROR ); usageCallback( a_pszArgv[ 0 ] ); return -1; } g_pszFile = strdup( a_pszArgv[ optind ] ); return 0;}/* * findExistingObjects * Search for objects of the supplied type that have a SUBJECT * and ID attribute equal to the values of the object to be * imported. */intfindExistingObjects( CK_SESSION_HANDLE a_hSession, CK_ATTRIBUTE *a_tAttr, CK_ULONG a_ulAttrCount, CK_OBJECT_HANDLE **a_phObject, CK_ULONG *a_pulObjectCount ) { CK_RV rv; CK_BBOOL bTrue = TRUE; // Set up default search attributes CK_ATTRIBUTE tDefaultAttr[] = { { CKA_TOKEN, &bTrue, sizeof( bTrue ) }, { CKA_SUBJECT, g_pchSubject, g_ulSubjectLen }, { CKA_ID, g_pchId, g_ulIdLen }, }; CK_ULONG ulDefaultAttrCount = sizeof( tDefaultAttr ) / sizeof( CK_ATTRIBUTE ); CK_ATTRIBUTE tAttr[ ulDefaultAttrCount + a_ulAttrCount ]; CK_ULONG ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE ); *a_phObject = NULL; *a_pulObjectCount = 0; // Apply attributes and search memcpy( tAttr, tDefaultAttr, ulDefaultAttrCount * sizeof( CK_ATTRIBUTE ) ); if ( a_ulAttrCount ) memcpy( tAttr + ulDefaultAttrCount, a_tAttr, a_ulAttrCount * sizeof( CK_ATTRIBUTE ) ); rv = findObjects( a_hSession, tAttr, ulAttrCount, a_phObject, a_pulObjectCount ); return ( rv == CKR_OK ) ? 0 : -1;}/* * checkExistingObjects * Use findExistingObjects to determine if objects of the * supplied type currently exist. If so, prompt the user as * to whether to replace the existing objects. */intcheckExistingObjects( CK_SESSION_HANDLE a_hSession, CK_ATTRIBUTE *a_tAttr, CK_ULONG a_ulAttrCount, const char *a_pszObject ) { int rc = -1; CK_OBJECT_HANDLE *phObject = NULL; CK_ULONG ulObjectCount = 0; char szPrompt[ strlen( TOKEN_ID_PROMPT ) + strlen( a_pszObject ) + 1 ]; char *pszReply = NULL; if ( g_bAttrsValid ) { // Search for existing objects if ( findExistingObjects( a_hSession, a_tAttr, a_ulAttrCount, &phObject, &ulObjectCount ) == -1 ) goto out; if ( ulObjectCount > 0 ) { // One or more objects exists if ( !g_bYes ) { // Prompt for whether to replace the existing objects sprintf( szPrompt, TOKEN_ID_PROMPT, a_pszObject ); pszReply = getReply( szPrompt, 1 ); if ( !pszReply || ( strlen( pszReply ) == 0 ) || ( strcasecmp( pszReply, TOKEN_ID_NO ) == 0 ) ) { goto out; } } } } rc = 0;out: free( phObject ); free( pszReply ); return rc;}/* * destroyExistingObjects * Use findExistingObjects to locate all objects of the * supplied type that currently exists and destroy them. */intdestroyExistingObjects( CK_SESSION_HANDLE a_hSession, CK_ATTRIBUTE *a_tAttr, CK_ULONG a_ulAttrCount ) { int rc = -1; CK_RV rv; CK_OBJECT_HANDLE *phObject = NULL; CK_ULONG ulObjectCount = 0; if ( g_bAttrsValid ) { // Search for existing objects if ( findExistingObjects( a_hSession, a_tAttr, a_ulAttrCount, &phObject, &ulObjectCount ) == -1 ) goto out; // Destroy each object found while ( ulObjectCount > 0 ) { rv = destroyObject( a_hSession, phObject[ --ulObjectCount ] ); if ( rv != CKR_OK ) goto out; } } rc = 0;out: free( phObject ); return rc;}/* * readX509Cert * Use the OpenSSL library to read a PEM formatted X509 certificate. */intreadX509Cert( const char *a_pszFile, int a_bCheckKey, X509 **a_pX509 ) { int rc = -1; FILE *pFile = stdin; X509 *pX509 = NULL; EVP_PKEY *pKey = NULL; *a_pX509 = NULL; // Open the file to be read if ( a_pszFile ) { errno = 0; pFile = fopen( a_pszFile, "r" ); if ( !pFile ) { logError( TOKEN_FILE_OPEN_ERROR, a_pszFile, strerror( errno ) ); goto out; } } // Read the X509 certificate pX509 = PEM_read_X509( pFile, NULL, NULL, NULL ); if ( !pX509 ) { unsigned long ulError = ERR_get_error( ); // Not necessarily an error if the file doesn't contain the cert if ( ( ERR_GET_LIB( ulError ) == ERR_R_PEM_LIB ) && ( ERR_GET_REASON( ulError ) == PEM_R_NO_START_LINE ) ) { logInfo( TOKEN_OPENSSL_ERROR, ERR_error_string( ulError, NULL ) ); rc = 0; } else logError( TOKEN_OPENSSL_ERROR, ERR_error_string( ulError, NULL ) ); goto out; } // Make sure the certificate uses an RSA key if ( !a_bCheckKey ) { rc = 0; goto out; } pKey = X509_get_pubkey( pX509 ); if ( !pKey ) { logInfo( TOKEN_OPENSSL_ERROR, ERR_error_string( ERR_get_error( ), NULL ) ); X509_free( pX509 ); pX509 = NULL; goto out; } if ( EVP_PKEY_type( pKey->type ) != EVP_PKEY_RSA ) { logError( TOKEN_RSA_KEY_ERROR ); X509_free( pX509 ); pX509 = NULL; goto out; } rc = 0;out: *a_pX509 = pX509; if ( a_pszFile && pFile ) fclose( pFile ); return rc;}/* * checkX509Cert * Use checkExistingObjects to search for X_509 objects * that match the attributes of the X_509 object to be imported. */intcheckX509Cert( CK_SESSION_HANDLE a_hSession ) { CK_CERTIFICATE_TYPE tX509 = CKC_X_509; CK_ATTRIBUTE tAttr[] = { { CKA_CERTIFICATE_TYPE, &tX509, sizeof( tX509 ) }, }; CK_ULONG ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE ); return checkExistingObjects( a_hSession, tAttr, ulAttrCount, TOKEN_ID_X509_CERT );}/* * destroyX509CertObject * Use destroyExistingObjects to destroy X_509 objects * that match the attributes of the X_509 object to be imported. */intdestroyX509CertObject( CK_SESSION_HANDLE a_hSession ) { CK_CERTIFICATE_TYPE tX509 = CKC_X_509; CK_ATTRIBUTE tAttr[] = { { CKA_CERTIFICATE_TYPE, &tX509, sizeof( tX509 ) }, }; CK_ULONG ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE ); return destroyExistingObjects( a_hSession, tAttr, ulAttrCount );}/* * createX509CertObject * Create an X_509 object. */intcreateX509CertObject( X509 *a_pX509, CK_SESSION_HANDLE a_hSession ) { int rc = -1; CK_RV rv; CK_BBOOL bTrue = TRUE; X509_NAME *pIssuer = NULL; ASN1_INTEGER *pSerialNum = NULL; CK_BYTE *pchIssuer = NULL; CK_ULONG ulIssuerLen = 0; CK_BYTE *pchSerialNum = NULL; CK_ULONG ulSerialNumLen = 0; CK_BYTE *pchCert = NULL; CK_ULONG ulCertLen = 0; CK_OBJECT_CLASS clCertClass = CKO_CERTIFICATE; CK_CERTIFICATE_TYPE tCertType = CKC_X_509; CK_BBOOL bPrivate = ( !g_bPublic ) ? TRUE : FALSE; // The issuer, serial number, and value attributes must be completed // before the object is created CK_ATTRIBUTE tCertAttr[] = { { CKA_CLASS, &clCertClass, sizeof( clCertClass ) }, { CKA_TOKEN, &bTrue, sizeof( bTrue ) }, { CKA_PRIVATE, &bPrivate, sizeof( bPrivate ) }, { CKA_MODIFIABLE, &bTrue, sizeof( bTrue ) }, { CKA_LABEL, g_pchName, g_ulNameLen }, { CKA_CERTIFICATE_TYPE, &tCertType, sizeof( tCertType ) }, { CKA_SUBJECT, g_pchSubject, g_ulSubjectLen }, { CKA_ID, g_pchId, g_ulIdLen }, { CKA_ISSUER, NULL, 0 }, { CKA_SERIAL_NUMBER, NULL, 0 }, { CKA_VALUE, NULL, 0 }, }; CK_ULONG ulCertAttrCount = sizeof( tCertAttr ) / sizeof( CK_ATTRIBUTE ); CK_OBJECT_HANDLE hObject; // Get the issuer name from the X509 certificate pIssuer = X509_get_issuer_name( a_pX509 ); if ( !pIssuer ) { logError( TOKEN_OPENSSL_ERROR, ERR_error_string( ERR_get_error( ), NULL ) ); goto out; } ulIssuerLen = i2d_X509_NAME( pIssuer, &pchIssuer ); if ( ulIssuerLen < 0 ) { logError( TOKEN_OPENSSL_ERROR, ERR_error_string( ERR_get_error( ), NULL ) ); goto out; } // Get the serial number from the X509 certificate pSerialNum = X509_get_serialNumber( a_pX509 ); if ( !pSerialNum ) { logError( TOKEN_OPENSSL_ERROR, ERR_error_string( ERR_get_error( ), NULL ) ); goto out; } ulSerialNumLen = i2d_ASN1_INTEGER( pSerialNum, &pchSerialNum ); if ( ulSerialNumLen < 0 ) { logError( TOKEN_OPENSSL_ERROR, ERR_error_string( ERR_get_error( ), NULL ) ); goto out; } // Get a DER encoded format of the X509 certificate ulCertLen = i2d_X509( a_pX509, &pchCert ); if ( ulCertLen < 0 ) { logError( TOKEN_OPENSSL_ERROR, ERR_error_string( ERR_get_error( ), NULL ) ); goto out; } // Set the attribute values tCertAttr[ 8 ].pValue = pchIssuer; tCertAttr[ 8 ].ulValueLen = ulIssuerLen; tCertAttr[ 9 ].pValue = pchSerialNum; tCertAttr[ 9 ].ulValueLen = ulSerialNumLen; tCertAttr[ 10 ].pValue = pchCert; tCertAttr[ 10 ].ulValueLen = ulCertLen; // Create the X509 certificate object rv = createObject( a_hSession, tCertAttr, ulCertAttrCount, &hObject ); if ( rv != CKR_OK ) goto out; rc = 0;out: OPENSSL_free( pchIssuer ); OPENSSL_free( pchCert ); OPENSSL_free( pchSerialNum ); return rc;}/* * doX509Cert * Process an X509 certificate for import. */intdoX509Cert( X509 *a_pX509, CK_SESSION_HANDLE a_hSession ) { int rc = -1; if ( destroyX509CertObject( a_hSession ) == -1 ) goto out; if ( createX509CertObject( a_pX509, a_hSession ) == -1 ) goto out; rc = 0;out: return rc;}/* * readRsaKey * Use the OpenSSL library to read a PEM formatted RSA key. */intreadRsaKey( const char *a_pszFile, RSA **a_pRsa ) { int rc = -1; FILE *pFile = stdin; RSA *pRsa = NULL; *a_pRsa = NULL; // Open the file to be read if ( a_pszFile ) { errno = 0; pFile = fopen( a_pszFile, "r" ); if ( !pFile ) { logError( TOKEN_FILE_OPEN_ERROR, a_pszFile, strerror( errno ) ); goto out; } } // Read the RSA key // This reads the public key also, not just the private key pRsa = PEM_read_RSAPrivateKey( pFile, NULL, NULL, NULL ); if ( !pRsa ) { unsigned long ulError = ERR_get_error( ); // Not necessarily an error if the file doesn't contain the key if ( ( ERR_GET_LIB( ulError ) == ERR_R_PEM_LIB ) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -