Developer's Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ex-kmip-15.c
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "p6com.h"
#include "p6loader.h" // Standalone Component Loader definitions
#include "p6regex.h" // Narrow string regular expression interfaces
#include "p6wregex.h" // Wide string regular expression interfaces
#include "p6split.h" // Narrow split and and explode using regex
#include "p6wsplit.h" // Wide split and and explode using wregex
#include "p6jsonreader.h" // Streaming JSON parser interfaces
#include "p6loader.h" // Standalone Component Loader definitions
#include "p6sax2contenthandler.h" // SAX2 content handler definitions
#include "p6sax2xmlreader.h" // Definitions for the main SAX2 interface
#include "p6sax2errorhandler.h" // SAX2 error handler definitions
#include "p6domxml.h" // DOM Parser interface definitions
#include "p6xmlnode.h" // XML and JSON node definitions
#include "p6xpathexpression.h" // XPATH 2.0 expression compilation interface definitions
#include "p6domnodeset.h" // DOM node enumeration interface definitions
#include "p6domnodesetsort.h" // DOM Node sorting interface definitions
#include "p6keystore.h"
#include "p6kmip.h"
#include "p6kmipclient.h"
#include "p6config.h"
#include "p6file.h"
#include "p6dir.h"
#include "p6genkeys.h"
#include "cconsolestream.h"
P6DECLARE_IID( p6ICom );
P6DECLARE_IID( p6IKMIPRequest );
P6DECLARE_CID( p6KMIPClient );
P6DECLARE_IID( p6IKMIPClient );
P6DECLARE_IID( p6ISafeString );
P6DECLARE_CID( p6EntropySource );
P6DECLARE_IID( p6IEntropySource );
P6DECLARE_CID( p6Random );
P6DECLARE_IID( p6IRandomInit );
P6DECLARE_IID( p6IRandom );
P6DECLARE_IID( p6IRunningIface );
P6DECLARE_CID( p6Cert );
P6DECLARE_IID( p6ICert );
P6DECLARE_IID( p6ICertInit );
P6DECLARE_CID( p6GenKeys );
P6DECLARE_IID( p6IGenKeys );
P6DECLARE_CID( p6Sign );
P6DECLARE_IID( p6ISign );
P6DECLARE_CID( p6SymmetricCrypto );
P6DECLARE_IID( p6ISymmetricCrypto );
P6DECLARE_CID( p6CryptoKey );
P6DECLARE_IID( p6ICryptoKey );
P6DECLARE_IID( p6ICryptoKeyInit );
P6DECLARE_CID( p6Dir );
P6DECLARE_IID( p6IDir );
P6DECLARE_CID( p6UnbufferedFile );
P6DECLARE_IID( p6IUnbufferedFile );
P6DECLARE_IID( p6IKeystoreInit );
P6DECLARE_IID( p6IKeystore );
P6DECLARE_CID( p6Keystore );
P6DECLARE_IID( p6IKeystoreSSL );
P6DECLARE_IID( p6IDataStream );
// Global variables
static p6ISafeString *m_pStr = NULL; // -> P6R generic string library
static p6IRandom *m_pRandom = NULL; // -> crypto related to generate keys
static p6ICryptoKey *m_pSignKey = NULL; // -> keystore related
static p6ISymmetricCrypto *m_pCrypto = NULL; // -> used to encrypt the contents of the keystore
static P6UINT32 m_port = 0; // -> KMIP server port to connect to
static P6UINT32 m_compatMask = 0; // -> compatibility mask: 0 use TTLV message encoding, 1 TTLV over HTTP, 2 use XML message encoding, 4 use JSON message encoding
static P6WCHAR* m_pHostName = NULL; // -> IP address or FQDN of KMIP server to connect to
static p6IKeystore *m_pKeystore = NULL; // -> the KMIP client requires that a properly initialzed keystore is setup
static p6IKeystoreInit *m_pStoreInit = NULL; // -> keystore related
//
static P6ERR getSafeString( p6ISafeString **ppStr /*out*/ )
{
P6ERR err = eFail;
if ( P6SUCCEEDED( err = p6GetRuntimeIface( &IID_p6ISafeString, (P6VOID**)ppStr )))
printf("getSafeString [ OK ]\n");
else printf("getSafeString [ FAILED ] %x\n",err);
return err;
}
// Key generation requires an entropy source
static P6ERR getRNG( p6IRandom **ppRandom /*out*/ )
{
P6ERR err = eFail;
p6IEntropySource *pSource = NULL;
p6IRandomInit *pInit = NULL;
if (P6SUCCEEDED( err = p6CreateCryptoInstance( &CID_p6EntropySource, &IID_p6IEntropySource, (P6VOID**)&pSource )))
{
if (P6SUCCEEDED( err = pSource->lpVtbl->initialize( pSource, P6ENTROPY_HIGH )))
{
if (P6SUCCEEDED( err = p6CreateCryptoInstance( &CID_p6Random, &IID_p6IRandomInit, (P6VOID**)&pInit )))
{
if (P6SUCCEEDED( err = pInit->lpVtbl->initialize( pInit, P6RAND_NOFLAGS, pSource ))) {
err = pInit->lpVtbl->queryInterface( pInit, &IID_p6IRandom, (P6VOID**)ppRandom );
}
}
}
}
if (NULL != pSource) pSource->lpVtbl->release( pSource );
if (NULL != pInit ) pInit->lpVtbl->release( pInit );
return err;
}
// The contents of the keystore is protected by a key
P6ERR getIGenKeys( p6IGenKeys **ppGenKeys /*out*/ )
{
P6ERR err = eFail;
p6IGenKeys *pTempKeys = NULL;
*ppGenKeys = NULL;
// Create an instance of the p6IGenKeys interface and then initialize it for use
if (P6SUCCEEDED( err = p6CreateCryptoInstance( &CID_p6GenKeys, &IID_p6IGenKeys, (P6VOID**)&pTempKeys )))
{
if (P6FAILED( err = pTempKeys->lpVtbl->initialize( pTempKeys, P6GENKEY_NOFLAGS, m_pRandom ))) {
pTempKeys->lpVtbl->release( pTempKeys );
}
else {
*ppGenKeys = pTempKeys;
}
}
return err;
}
// Create the key file (supplied by the server vendor) into a p6ICryptoKey object for SSL
//
P6ERR createPKCS8Key( P6BSTR keyBuffer, P6SIZE keySize, p6ICryptoKey **ppNewKey )
{
P6ERR err = eFail;
p6ICryptoKeyInit *pKeyInit = NULL;
if (P6SUCCEEDED( err = p6CreateCryptoInstance( &CID_p6CryptoKey, &IID_p6ICryptoKeyInit, (P6VOID**)&pKeyInit )))
{
if (P6SUCCEEDED( err = pKeyInit->lpVtbl->initialize( pKeyInit, P6CKF_NONE, m_pRandom )))
{
if (P6SUCCEEDED( err = pKeyInit->lpVtbl->loadPKCS8Key( pKeyInit, keyBuffer.pString, (P6UINT32)keyBuffer.length, (P6UINT32)keySize ))) {
err = pKeyInit->lpVtbl->queryInterface( pKeyInit, &IID_p6ICryptoKey, (P6VOID**)ppNewKey );
}
}
}
return err;
}
// Load KMIP credentials into the keystore for the TLS server connection
P6ERR keystoreAddRootCertFromFile( p6IKeystore *pKeystore, const P6WCHAR *pszCertificateFile )
{
P6ERR err = eFail;
P6WCHAR certPath[P6MAXPATH+2] = {0};
p6IKeystoreSSL *pSSLHelp = NULL;
if (NULL == pKeystore || NULL == pszCertificateFile) return eInvalidArg;
if (P6FAILED( err = p6GetDirectory( P6D_CONF, certPath, P6MAXPATH, NULL ))) return err;
if (P6FAILED( err = m_pStr->lpVtbl->wstrlcat( m_pStr, certPath, P6CNTOF(certPath), (const P6WCHAR*)P6TEXT("/"), NULL ))) return err;
if (P6FAILED( err = m_pStr->lpVtbl->wstrlcat( m_pStr, certPath, P6CNTOF(certPath), pszCertificateFile, NULL ))) return err;
if (P6FAILED( err = pKeystore->lpVtbl->queryInterface( pKeystore, &IID_p6IKeystoreSSL, (P6VOID**)&pSSLHelp ))) return err;
err = pSSLHelp->lpVtbl->importTrustedRootCertFromPEMFile( pSSLHelp, certPath, NULL );
pSSLHelp->lpVtbl->release( pSSLHelp );
return err;
}
// Load KMIP credentials into the keystore for the TLS server connection
P6ERR keystoreAddClientCertFromFile( p6IKeystore* pKeystore, const P6WCHAR* pszHostname, const P6WCHAR* pszPrivateKeyFile, const P6WCHAR* pszCertificateFile )
{
P6ERR err = eFail;
P6WCHAR certPath[P6MAXPATH+2] = {0};
P6WCHAR keyPath[P6MAXPATH+2] = {0};
p6IKeystoreSSL *pSSLHelp = NULL;
if (NULL == pKeystore || NULL == pszHostname || NULL == pszPrivateKeyFile || NULL == pszCertificateFile ) return eInvalidArg;
if (P6FAILED( err = p6GetDirectory( P6D_CONF, keyPath, P6MAXPATH, NULL ))) return err;
if (P6FAILED( err = m_pStr->lpVtbl->wstrlcat( m_pStr, keyPath, P6CNTOF(keyPath), (const P6WCHAR*)P6TEXT("/"), NULL ))) return err;
if (P6FAILED( err = m_pStr->lpVtbl->wstrlcat( m_pStr, keyPath, P6CNTOF(keyPath), pszPrivateKeyFile, NULL ))) return err;
if (P6FAILED( err = p6GetDirectory( P6D_CONF, certPath, P6MAXPATH, NULL ))) return err;
if (P6FAILED( err = m_pStr->lpVtbl->wstrlcat( m_pStr, certPath, P6CNTOF(certPath), (const P6WCHAR*)P6TEXT("/"), NULL ))) return err;
if (P6FAILED( err = m_pStr->lpVtbl->wstrlcat( m_pStr, certPath, P6CNTOF(certPath), pszCertificateFile, NULL ))) return err;
if (P6FAILED( err = pKeystore->lpVtbl->queryInterface( pKeystore, &IID_p6IKeystoreSSL, (P6VOID**)&pSSLHelp ))) return err;
err = pSSLHelp->lpVtbl->importCredentialsPEM( pSSLHelp, P6TRUE, pszHostname, keyPath, certPath, NULL, NULL );
pSSLHelp->lpVtbl->release( pSSLHelp );
return err;
}
// Create a keystore and then load it with the information we need to connect to the KMIP server.
// P6R's SSL looks into the keystore for certificates and the private key when it starts a connection to the KMIP server.
P6ERR createKeystore( const P6WCHAR* pKeystoreName, const P6WCHAR* rootPEM, const P6WCHAR* certPEM, const P6WCHAR* privPEM, p6IKeystoreInit** ppInit /*out*/, p6IKeystore** ppKeystore /*out*/ )
{
P6ERR err = eFail;
*ppInit = NULL;
*ppKeystore = NULL;
// Create the keystore and fill it with vendor provided SSL certificates
if (P6FAILED( err = p6CreateInstance( NULL, &CID_p6Keystore, &IID_p6IKeystoreInit, (P6VOID**)ppInit ))) return err;
err = (*ppInit)->lpVtbl->queryInterface( (*ppInit), &IID_p6IKeystore, (P6VOID**)ppKeystore );
if (P6FAILED( err = (*ppInit)->lpVtbl->initialize( (*ppInit), P6KEYSTORE_NOFLAGS, m_pCrypto, SH_SHA256, m_pSignKey )))
{
if (NULL != (*ppKeystore)) (*ppKeystore)->lpVtbl->release( (*ppKeystore) );
(*ppKeystore) = NULL;
(*ppInit)->lpVtbl->release( (*ppInit) );
(*ppInit) = NULL;
return err;
}
/*
* The first parameter of openSigned() is the file path where to create and access keystore databases.
* If NULL, then the keystore location will default to the P6R database directory (i.e., the "db" sub-directory).
* If the SKC is installed in a read-only directory then the first parameter will need to be set to
* an existing read/write directory.
*/
if (P6FAILED( err = (*ppInit)->lpVtbl->openSigned( (*ppInit), NULL, pKeystoreName )))
{
if (NULL != (*ppKeystore)) (*ppKeystore)->lpVtbl->release( (*ppKeystore) );
(*ppKeystore) = NULL;
(*ppInit)->lpVtbl->release( (*ppInit) );
(*ppInit) = NULL;
return err;
}
if (P6FAILED( err = keystoreAddRootCertFromFile( (*ppKeystore), rootPEM ))) return err;
if (P6FAILED( err = keystoreAddClientCertFromFile( (*ppKeystore), m_pHostName, privPEM, certPEM ))) return err;
return eOk;
}
// Clean up after the example is over
P6VOID freeGlobals()
{
if (NULL != m_pStr ) m_pStr->lpVtbl->release( m_pStr );
if (NULL != m_pRandom ) m_pRandom->lpVtbl->release( m_pRandom );
if (NULL != m_pSignKey ) m_pSignKey->lpVtbl->release( m_pSignKey );
if (NULL != m_pCrypto ) m_pCrypto->lpVtbl->release( m_pCrypto );
if (NULL != m_pStoreInit) m_pStoreInit->lpVtbl->release( m_pStoreInit );
if (NULL != m_pKeystore ) m_pKeystore->lpVtbl->release( m_pKeystore );
}
// Replace the host name of "fqdn.com" to the fully qualified domain name of the server you wish to connect to.
P6ERR initialize()
{
P6ERR err = eOk;
P6WCHAR dbPath[P6MAXPATH+20] = {0};
p6IGenKeys* pGenKey = NULL;
p6ICryptoKey* pKey = NULL;
p6IDir* pDir = NULL;
// [A] Right now configuration is hard coded, but could read out of a config file later
// m_compatMask is set to zero for TTLV message encoding, set to 2 for XML message encoding, and set to 4 for JSON message encoding
//
if (P6FAILED( err = getSafeString( &m_pStr ))) return err;
if (P6FAILED( err = getRNG( &m_pRandom ))) return err;
m_port = 5696;
m_compatMask = 0;
if (P6FAILED( err = m_pStr->lpVtbl->wstrdup( m_pStr, (const P6WCHAR*)P6TEXT("fqdn.com"), &m_pHostName ))) return err;
// [B} Create the keys required to encrypt the contents of the keystore
if (P6FAILED( err = getIGenKeys( &pGenKey ))) return err;
if (P6SUCCEEDED( err = pGenKey->lpVtbl->genSymmetricKey( pGenKey, &m_pSignKey, 256, P6FALSE ))) {
err = pGenKey->lpVtbl->genSymmetricKey( pGenKey, &pKey, 256, P6FALSE );
}
err = pGenKey->lpVtbl->release( pGenKey );
if (P6SUCCEEDED( err )) err = p6CreateCryptoInstance( &CID_p6SymmetricCrypto, &IID_p6ISymmetricCrypto, (P6VOID**)&m_pCrypto );
if (P6SUCCEEDED( err )) err = m_pCrypto->lpVtbl->initialize( m_pCrypto, P6SYM_NOPADDING, CIPHER_AES_CFB );
if (P6SUCCEEDED( err )) err = m_pCrypto->lpVtbl->setKey( m_pCrypto, pKey );
if (NULL != pKey) pKey->lpVtbl->release( pKey );
if (P6FAILED( err )) return err;
// [C] Initialize the keystore with keys provided to us by the server vendor, clean up any previous keystore from running this example
if (P6FAILED( err = p6CreateInstance( NULL, &CID_p6Dir, &IID_p6IDir, (P6VOID**)&pDir ))) return err;
if (P6FAILED( err = pDir->lpVtbl->initialize( pDir ))) {
pDir->lpVtbl->release( pDir );
return err;
}
dbPath[0] = '\0';
if (P6FAILED( err = p6GetDirectory( P6D_DATA, dbPath, P6MAXPATH, NULL ))) {
pDir->lpVtbl->release( pDir );
return err;
}
if (P6FAILED( err = m_pStr->lpVtbl->wstrlcat( m_pStr, dbPath, P6CNTOF(dbPath), (const P6WCHAR*)P6TEXT("/db/KMIP12_keystore"), NULL ))) {
pDir->lpVtbl->release( pDir );
return err;
}
pDir->lpVtbl->unlink( pDir, dbPath );
dbPath[0] = '\0';
if (P6FAILED( err = p6GetDirectory( P6D_DATA, dbPath, P6MAXPATH, NULL ))) {
pDir->lpVtbl->release( pDir );
return err;
}
if (P6FAILED( err = m_pStr->lpVtbl->wstrlcat( m_pStr, dbPath, P6CNTOF(dbPath), (const P6WCHAR*)P6TEXT("/db/KMIP12_keystore.sig"), NULL ))) {
pDir->lpVtbl->release( pDir );
return err;
}
pDir->lpVtbl->unlink( pDir, dbPath );
pDir->lpVtbl->release( pDir );
err = createKeystore( (const P6WCHAR*)P6TEXT("KMIP12_keystore"), (const P6WCHAR*)P6TEXT("RootCert.pem"), (const P6WCHAR*)P6TEXT("ClientCert.pem"), (const P6WCHAR*)P6TEXT("ClientPrivate.pem"), &m_pStoreInit, &m_pKeystore );
return err;
}
// The client creates an SSL connection to the KMIP server and then makes its requests
// Configure the client on how it is supposed to behave (e.g., protocol version, use TTLV or XML or JSON, how to encode keys PKCSXXX).
//
P6ERR setPreferences( P6KMIP_PREF *pPrefs, const P6WCHAR* pLogDir, P6UINT16 asynchronous, P6UINT32 privateKeyEncoding, P6UINT32 publicKeyEncoding,
P6UINT32 symmetricKeyEncoding, P6UINT32 maxBufferSize, P6UINT32 connectTimeout, P6UINT32 sendTimeout, P6UINT32 receiveTimeout,
P6UINT32 initialBufCount, P6UINT32 growBufsBy )
{
m_pStr->lpVtbl->setMem( m_pStr, pPrefs, 0, sizeof( P6KMIP_PREF ));
pPrefs->pVersion = "1.2"; pPrefs->pSubdirectory = pLogDir;
pPrefs->asynchronous = asynchronous; pPrefs->maxBufferSize = maxBufferSize;
pPrefs->connectTimeout = connectTimeout; pPrefs->sendTimeout = sendTimeout;
pPrefs->receiveTimeout = receiveTimeout; pPrefs->initialBufCount = initialBufCount;
pPrefs->growBufsBy = growBufsBy; pPrefs->privateKeyEncoding = privateKeyEncoding;
pPrefs->publicKeyEncoding = publicKeyEncoding; pPrefs->symmetricKeyEncoding = symmetricKeyEncoding;
pPrefs->compatibility1 = m_compatMask;
return eOk;
}
// We just hard code the credentials (i.e., name and password) for a test if needed
P6ERR createSession( p6IKMIPClient *pClient, P6BOOL bWithCredentials )
{
P6ERR err = eFail;
P6KMIP_CREDENTIAL credential;
// -> integration testing setups are often not production quality, some use IP addresses instead of FQDN and thus a non-secure setup
// -> for production remove the flag P6SSF_VRFY_DISABLEHOSTMATCH
if (P6FAILED( err = pClient->lpVtbl->setSSLOptions( pClient, NULL, (P6SSF_METHOD_TLS1 | P6SSF_SECURE_CLIENT | P6SSF_SECURE_CLIENT_AUTH | P6SSF_LOG_X509SUBJECTLOOKUPS | P6SSF_VRFY_DISABLEHOSTMATCH)))) return err;
m_pStr->lpVtbl->setMem( m_pStr, &credential, 0, sizeof( P6KMIP_CREDENTIAL ));
credential.type = 1;
credential.value.password.userName.pString = "Fred";
credential.value.password.userName.length = 4;
credential.value.password.password.pString = "password1";
credential.value.password.password.length = 9;
return pClient->lpVtbl->open( pClient, m_pHostName, m_port, (bWithCredentials ? &credential : NULL));
}
// Just return the very first unique identifier from the enumerator
// Some calls can result in multiple unique identifiers returned at the same time (e.g., locate object)
P6ERR extractUniqueId( p6IKMIPStr *pEnum, P6NCSTR *pUniqueId )
{
P6ERR err = eFail;
P6CHAR* pGUID = NULL;
P6NCSTR buffer = { NULL, 0 };
pUniqueId->pString = NULL;
pUniqueId->length = 0;
err = pEnum->lpVtbl->reset( pEnum );
err = pEnum->lpVtbl->next( pEnum, &buffer );
if ( 0 < buffer.length )
{
if (NULL == (pGUID = (P6CHAR*)malloc( sizeof(P6CHAR) * (buffer.length + 2) ))) return eNoMemory;
pGUID[0] = 0;
buffer.pString = pGUID;
buffer.length += 2;
if (P6FAILED( err = pEnum->lpVtbl->next( pEnum, &buffer ))) return err;
pUniqueId->pString = buffer.pString;
pUniqueId->length = buffer.length;
}
else err = eFail;
return err;
}
// Query the KMIP server for the State attribute associated with the key represented by the keyId
// unique identifier.
//
P6VOID verifyStateAttribute( p6IKMIPClient *pClient, P6NCSTR keyId, P6UINT32 expectedState )
{
P6KMIP_RESULT resultCodes;
P6KMIP_ATTRIBRESULT getResult;
P6KMIP_GETATTRIBPARAMS attribParams;
P6KMIP_OBJECT_ATTRIBUTE objAttribute;
P6NCSTR attribNames[2];
P6UINT32 attribType = 0;
P6ERR err = eOk;
// -> here we need to identify the attribute by its String literal, allows us to get attributes starting with "X-"
attribNames[0].pString = "State";
attribNames[0].length = 5;
m_pStr->lpVtbl->setMem( m_pStr, &resultCodes, 0, sizeof( P6KMIP_RESULT ));
m_pStr->lpVtbl->setMem( m_pStr, &getResult, 0, sizeof( P6KMIP_ATTRIBRESULT ));
m_pStr->lpVtbl->setMem( m_pStr, &attribParams, 0, sizeof( P6KMIP_GETATTRIBPARAMS ));
attribParams.uniqueId = keyId;
attribParams.attribCount = 1;
attribParams.pAttributeNames = attribNames;
if (P6SUCCEEDED( err = pClient->lpVtbl->getAttributes( pClient, attribParams, &getResult, &resultCodes )))
{
if (NULL != getResult.pAttribute)
{
if (P6SUCCEEDED( err = getResult.pAttribute->lpVtbl->next( getResult.pAttribute, &attribType )))
{
m_pStr->lpVtbl->setMem( m_pStr, &objAttribute, 0, sizeof( P6KMIP_OBJECT_ATTRIBUTE ));
if (KMIP_ATTRIB_STATE == attribType )
{
err = getResult.pAttribute->lpVtbl->getValue( getResult.pAttribute, &objAttribute );
if (expectedState != objAttribute.value.state) {
printf("\nExample 15, expected state is %d but the key has %d\n", expectedState, objAttribute.value.state );
}
}
}
getResult.pAttribute->lpVtbl->release( getResult.pAttribute );
}
}
}
// Have the KMIP server create a symmetric key and return its unique identifier.
// Main client function
// Similar to the KMIP TC_311_12 interop test case.
//
P6ERR run( p6IDataStream *pStreamDebug )
{
p6IKMIPClient* pClient = NULL;
p6IKMIPStr* pUniqueId = NULL;
P6KMIP_PREF preferences;
P6KMIP_RESULT resultCodes;
P6KMIP_KEYPARAMS keyParams;
P6KMIP_TEMPLATEATTRIBUTE attributes;
P6KMIP_ATTRIBUTE attributeList[4];
P6KMIP_NEWOBJECT newKey;
P6KMIP_REVOCATION reason;
P6NCSTR keyId = {NULL, 0};
P6ERR err = eOk;
// [1] Initialize, "TC_311_12" directory created in the configured log directory to hold all logs for this example
// -> the KMIP client is just a component, the using code can create any number of them as each is independent of all others
//
if (P6FAILED( err = p6CreateInstance( NULL, &CID_p6KMIPClient, &IID_p6IKMIPClient, (P6VOID**)&pClient ))) return err;
setPreferences( &preferences, P6CTEXT("TC_311_12"), 0, 0, 0, 0, 5000, 2000, 2000, 120000, 2, 2 );
if (P6FAILED( err = pClient->lpVtbl->initialize( pClient, (P6KMIPFLG_TRACE_MSGS | P6KMIPFLG_TRACE_FORMATKMIPXML), m_pKeystore, preferences ))) { // -> logging messages has to be turned on it defaults off
pClient->lpVtbl->release( pClient );
return err;
}
// [2] Open a connection to the KMIP server via SSL
if (P6FAILED( err = createSession( pClient, P6FALSE ))) {
pClient->lpVtbl->release( pClient );
return err;
}
// [3] Build the request (in this case a TTLV message), requesting a symmetric AES, 128 key to be created
m_pStr->lpVtbl->setMem( m_pStr, &resultCodes, 0, sizeof( P6KMIP_RESULT ));
m_pStr->lpVtbl->setMem( m_pStr, &newKey, 0, sizeof( P6KMIP_NEWOBJECT ));
m_pStr->lpVtbl->setMem( m_pStr, &keyParams, 0, sizeof( P6KMIP_KEYPARAMS ));
m_pStr->lpVtbl->setMem( m_pStr, &attributes, 0, sizeof( P6KMIP_TEMPLATEATTRIBUTE ));
// -> define all the attributes associated with the key to be created
// -> an attribute starting with a "x-" is defined a an extension and can be almost any type (e.g., time stamp)
attributeList[0].type = KMIP_ATTRIB_CRYPTOALGORITHM;
attributeList[0].index = 0;
attributeList[0].value.cryptoAlgorithm = KMIP_AES;
attributeList[1].type = KMIP_ATTRIB_CRYPTOLENGTH;
attributeList[1].index = 0;
attributeList[1].value.cryptoLength = 128;
attributeList[2].type = KMIP_ATTRIB_CRYPTOUSAGEMASK;
attributeList[2].index = 0;
attributeList[2].value.cryptoUsageMask = KMIP_USE_ENCRYPT | KMIP_USE_DECRYPT;
attributeList[3].type = KMIP_ATTRIB_EXTENSION;
attributeList[3].index = 0;
attributeList[3].value.extension.xName.pString = "x-ID";
attributeList[3].value.extension.xName.length = 4;
attributeList[3].value.extension.xValue.vText.pString = "TC-311-12";
attributeList[3].value.extension.xValue.vText.length = 9;
attributeList[3].value.extension.xType = KMIP_TYPE_TEXTSTRING;
attributes.attribCount = 4;
attributes.pAttributeList = attributeList;
keyParams.pAttributes = &attributes;
if (P6FAILED(err = pClient->lpVtbl->createKeyObject( pClient, keyParams, &newKey, &resultCodes ))) {
printf("\ncall to createKeyObject has failed %x\n", err );
}
else if (KMIP_RESULT_SUCCESS != resultCodes.resultStatus) {
printf("\nKMIP server returned an error\n");
}
// [4] Assuming the createKeyObject worked, extract the key's unique identifier from the enumerator
if (NULL != newKey.pUniqueId)
{
err = extractUniqueId( newKey.pUniqueId, &keyId );
newKey.pUniqueId->lpVtbl->release( newKey.pUniqueId );
newKey.pUniqueId = NULL;
}
// [5] Demonstrate how the state of the newly created key can be changed to active
verifyStateAttribute( pClient, keyId, KMIP_STATE_PREACTIVE );
m_pStr->lpVtbl->setMem( m_pStr, &resultCodes, 0, sizeof( P6KMIP_RESULT ));
err = pClient->lpVtbl->activateObject( pClient, keyId, NULL, &pUniqueId, &resultCodes );
if (NULL != pUniqueId) pUniqueId->lpVtbl->release( pUniqueId);
verifyStateAttribute( pClient, keyId, KMIP_STATE_ACTIVE );
// [6] For this test, if the key was created we need to clean up and remove it from the KMIP server
if (NULL != keyId.pString)
{
// -> we cannot just destroy an ACTIVE key, we MUST first change its state one way is to revoke it
m_pStr->lpVtbl->setMem( m_pStr, &resultCodes, 0, sizeof( P6KMIP_RESULT ));
m_pStr->lpVtbl->setMem( m_pStr, &reason, 0, sizeof( P6KMIP_REVOCATION ));
pUniqueId = NULL;
reason.reasonCode = KMIP_REVOC_UNSPECIFIED;
if ( P6FAILED( err = pClient->lpVtbl->revokeObject( pClient, keyId, reason, NULL, NULL, &pUniqueId, &resultCodes ))) {
printf("\ncall to revokeObject has failed %x\n", err );
}
else if (KMIP_RESULT_SUCCESS != resultCodes.resultStatus) {
printf("\nKMIP server returned an error on revoke key\n");
}
if (NULL != pUniqueId) pUniqueId->lpVtbl->release( pUniqueId );
m_pStr->lpVtbl->setMem( m_pStr, &resultCodes, 0, sizeof( P6KMIP_RESULT ));
err = pClient->lpVtbl->destroyObject( pClient, keyId, NULL, &newKey.pUniqueId, &resultCodes );
if (P6FAILED( err )) {
printf("\ndestroying key call has failed\n");
}
else if (KMIP_RESULT_SUCCESS != resultCodes.resultStatus) {
printf("\nKMIP server returned an error\n");
}
free( (P6VOID*)keyId.pString );
}
err = pClient->lpVtbl->close( pClient );
pClient->lpVtbl->release( pClient );
return err;
}
//
P6VOID KMIP_TC_311_12( p6IDataStream *pDataStream )
{
P6CHAR szTmp[32];
P6ERR err = eNotInitialized;
if (P6SUCCEEDED( err = initialize())) {
err = run( pDataStream );
}
freeGlobals();
printf( "KMIP client result: [ %s ]\n", p6ErrToStr(err, &szTmp[0], P6CHARCNT(szTmp)) );
}
//
int main(int argc,char *argv[])
{
P6ERR err = eFail;
p6IDataStream *pDataStream = NULL;
if (P6FAILED( err = createStream( &pDataStream ))) {
printf("ERROR: Failed to create a datastream [ %x ]\n", err );
return 1;
}
if ( P6SUCCEEDED( err = p6InitializeLoader( pDataStream, 9, P6SCLF_ALLLOG )))
{
KMIP_TC_311_12( pDataStream );
}
else printf("ERROR: Failed to initialize the loader [ %x ]\n", err );
return 0;
}