Developer's Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ex-kmip-5.cpp
#include <stdio.h>
#include <stdlib.h>
#include <memory> // nothrow
#include "p6skc.h"
#include "p6config.h"
#include "p6file.h"
#include "p6dir.h"
#include "p6gencerts.h"
#include "p6genkeys.h"
#include "cconsolestream.h"
using namespace P6R;
P6DECLARE_CID( p6KMIPClient );
P6DECLARE_CID( p6EntropySource );
P6DECLARE_CID( p6Random );
P6DECLARE_IID( p6IRunningIface );
P6DECLARE_CID( p6Cert );
P6DECLARE_CID( p6GenKeys );
P6DECLARE_CID( p6Sign );
P6DECLARE_CID( p6SymmetricCrypto );
P6DECLARE_CID( p6CryptoKey );
P6DECLARE_CID( p6Dir );
P6DECLARE_CID( p6UnbufferedFile );
P6DECLARE_CID( p6Keystore );
namespace {
class CKmipExample5
{
public:
P6CLASSMETHOD initialize();
P6CLASSMETHOD run( p6IDataStream *pStreamDebug );
CKmipExample5()
: m_port(0), m_compatMask(0), m_pHostName(NULL)
{ }
~CKmipExample5()
{
if (NULL != m_pHostName) m_cpStr->wstrfree( m_pHostName );
if (NULL != m_cpStoreInit) m_cpStoreInit->close();
}
protected:
// -> connection related
P6CLASSMETHOD createSession( p6IKMIPClient* pClient, P6BOOL bWithCredentials );
P6CLASSMETHOD setPreferences( P6KMIP_PREF* pPrefs, P6WCHAR* pLogDir, P6UINT16 asynchronous, P6UINT32 privateKeyEncoding, P6UINT32 publicKeyEncoding,
P6UINT32 symmetricKeyEncoding, P6UINT32 maxBufferSize, P6UINT32 connectTimeout, P6UINT32 sendTimeout, P6UINT32 receiveTimeout,
P6UINT32 initialBufCount, P6UINT32 growBufsBy );
// -> function used often to extract a unique id returned by the server
P6CLASSMETHOD extractUniqueId( p6IKMIPStr* pEnum, P6NCSTR* pUniqueId );
P6R::P6BOOL isEqualId( p6IKMIPStr* pUniqueId, P6NCSTR id );
// -> basic functions to find and free managed objects
P6CLASSMETHOD destroyObject( p6IKMIPClient* pClient, P6NCSTR objectId, P6BOOL bFree );
P6CLASSMETHOD revokeAnddestroyObject( p6IKMIPClient* pClient, P6NCSTR objectId, P6UINT32 code );
P6CLASSMETHOD locateAndFree( p6IKMIPClient* pClient, P6UINT32 objectType );
// -> crypto related
P6CLASSMETHOD getRNG(P6R::p6IRandom **ppRandom);
P6CLASSMETHOD getIGenKeys( p6IGenKeys** ppGenKeys );
// -> keystore related
P6CLASSMETHOD savePrivKeyInStore( p6IKeystore* pKeystore, const P6WCHAR* pNamespace, const P6WCHAR* pName, const P6WCHAR* pFilePath, P6UINT32 keySize );
P6CLASSMETHOD saveClientCertInStore( p6IKeystore* pKeystore, const P6WCHAR* pNamespace, const P6WCHAR* pName, const P6WCHAR* pFilePath );
P6CLASSMETHOD saveRootCertInStore( p6IKeystore* pKeystore, const P6WCHAR* pNamespace, const P6WCHAR* pFilePath );
P6CLASSMETHOD createKeystore( const P6WCHAR* pKeystoreName, const P6WCHAR* rootPEM, const P6WCHAR* certPEM, const P6WCHAR* privPEM, P6UINT32 privSize, p6IKeystoreInit** pInit, p6IKeystore** pKeystore );
P6CLASSMETHOD loadKeyFromFile( const P6WCHAR* pwszFilename, P6UINT32 keySize, p6ICryptoKey** ppNewKey );
P6CLASSMETHOD loadCertificateFromFile( const P6WCHAR* pPath, p6ICert** ppNewCert );
P6CLASSMETHOD createPKCS8Key( P6BSTR keyBuffer, P6SIZE keySize, p6ICryptoKey** ppNewKey );
p6ComPtr<p6ISafeString> m_cpStr; // -> generic string library
p6ComPtr<p6ISymmetricCrypto> m_cpCrypto; // -> used to encrypt the contents of the keystore
p6ComPtr<p6ICryptoKey> m_cpSignKey; // -> keystore related
p6ComPtr<p6IRandom> m_cpRandom; // -> crypto related
p6ComPtr<p6IKeystore> m_cpKeystore; // -> the KMIP client requires that a properly initialzed keystore is setup
p6ComPtr<p6IKeystoreInit> m_cpStoreInit; // -> keystore related
P6UINT32 m_port; // -> KMIP server port to connect to
P6UINT32 m_compatMask; // -> compatibility mask: 0 use TTLV message encoding, 2 use XML message encoding, 4 use JSON message encoding
P6WCHAR* m_pHostName; // -> IP address or FQDN of KMIP server to connect to
};
// Create the key file (supplied by the server vendor) into a p6ICryptoKey object for SSL
//
P6CLASSMETHODIMPL CKmipExample5::createPKCS8Key( P6BSTR keyBuffer, P6SIZE keySize, p6ICryptoKey** ppNewKey )
{
P6ERR err = eOk;
if (P6SUCCEEDED( err = p6CreateCryptoInstance( CID_p6CryptoKey, VALIDATECOMPTR( p6ICryptoKeyInit, cpKeyInit ))))
{
if (P6SUCCEEDED( err = cpKeyInit->initialize( P6CKF_NONE, m_cpRandom )))
{
if (P6SUCCEEDED( err = cpKeyInit->loadPKCS8Key( keyBuffer.pString, (P6UINT32) keyBuffer.length, (P6UINT32) keySize )))
{
err = cpKeyInit->queryInterface( VALIDATEIF( p6ICryptoKey, ppNewKey ));
}
}
}
return err;
}
// Load the KMIP server vendor supplied certificate file for SSL into a p6ICert object
//
P6CLASSMETHODIMPL CKmipExample5::loadCertificateFromFile( const P6WCHAR* pPath, p6ICert** ppNewCert )
{
P6ERR err = eOk;
if (P6FAILED( err = p6CreateCryptoInstance( CID_p6Cert, VALIDATECOMPTR( p6ICertInit, cpInit )))) return err;
if (P6FAILED( err = cpInit->initialize( P6CERT_NOFLAGS ))) return err;
if (P6SUCCEEDED( err = cpInit->loadCert( pPath ))) {
err = cpInit->queryInterface( VALIDATEIF( p6ICert, ppNewCert ));
}
return err;
}
// Load the PEM private key file (supplied by the server vendor) for SSL into a p6ICryptoKey object
//
P6CLASSMETHODIMPL CKmipExample5::loadKeyFromFile( const P6WCHAR* pwszFilename, P6UINT32 keySize, p6ICryptoKey** ppNewKey )
{
P6BSTR keyBuffer = {NULL, 0};
P6SIZE cBytesRead = 0;
P6ERR err = eNotFound;
if (NULL == pwszFilename) return eInvalidArg;
if (P6SUCCEEDED( err = p6CreateInstance( NULL, CID_p6UnbufferedFile, VALIDATECOMPTR( p6IUnbufferedFile, cpFile ))))
{
if (P6SUCCEEDED( err = cpFile->initialize()))
{
if (P6SUCCEEDED( err = cpFile->open( pwszFilename, P6FILE_READ|P6FILE_OPENEXISTING,P6FP_DEFAULT )))
{
P6FILEINFO info;
if ( P6SUCCEEDED( err = cpFile->stat( &info )))
{
if (info.m_cSize)
{
P6CHAR* pBuffer = new (std::nothrow) P6CHAR[(P6UINT32)info.m_cSize];
if ( pBuffer )
{
if (P6SUCCEEDED( err = cpFile->read( pBuffer,(P6UINT32)info.m_cSize, &cBytesRead )))
{
if (cBytesRead == info.m_cSize)
{
keyBuffer.length = cBytesRead;
keyBuffer.pString = (P6UCHAR*)pBuffer;
err = createPKCS8Key( keyBuffer, keySize, ppNewKey ); // or PKCS1?
}
}
}
else err = eIoError;
delete [] pBuffer;
}
else err = eNoMemory;
}
else {
err = eTooSmall;
}
cpFile->close();
}
}
}
return err;
}
// The contents of the keystore is protected by a key
P6CLASSMETHODIMPL CKmipExample5::getIGenKeys( p6IGenKeys** ppGenKeys )
{
P6ERR err = eOk;
*ppGenKeys = NULL;
err = p6CreateCryptoInstance( CID_p6GenKeys, VALIDATEIF( p6IGenKeys, ppGenKeys ));
if (P6SUCCEEDED(err))
{
err = (*ppGenKeys)->initialize( P6GENKEY_NOFLAGS, m_cpRandom );
if (P6FAILED( err ))
{
(*ppGenKeys)->release();
*ppGenKeys = NULL;
}
}
return err;
}
// Load in the certs we need to connect to the KMIP server into our new store
P6CLASSMETHODIMPL CKmipExample5::saveRootCertInStore( p6IKeystore* pKeystore, const P6WCHAR* pNamespace, const P6WCHAR* pFilePath )
{
P6WCHAR confPath[P6MAXPATH+2] = {0};
P6WCHAR szHash[20] = {0};
P6SIZE nHash = 0;
P6ERR err = eOk;
p6ComPtr<p6ICert> cpNewCert;
P6ARG args[2];
if (P6FAILED( err = p6GetDirectory( P6D_CONF, confPath, P6MAXPATH, NULL ))) return err;
if (P6FAILED( err = m_cpStr->wstrlcat( confPath, P6CNTOF(confPath), P6TEXT("/"), NULL ))) return err;
if (P6FAILED( err = m_cpStr->wstrlcat( confPath, P6CNTOF(confPath), pFilePath, NULL ))) return err;
if ( P6SUCCEEDED( err = loadCertificateFromFile( confPath, cpNewCert.addressof() )))
{
// SSL library expects a specific namespace depending on how the cert is used
// We store the root cert by the has of its subject which during the SSL protocol is what OpenSSL looks for
if (P6SUCCEEDED( err = cpNewCert->getSubjectHash( &nHash )))
{
P6AI_SIZE_HEXL( args, nHash );
if (P6SUCCEEDED( err = m_cpStr->formatStringW( szHash, P6CNTOF(szHash), NULL, P6TEXT("%1$"), args, 1 )))
err = pKeystore->setCertificate( pNamespace, szHash, cpNewCert, NULL );
}
}
return err;
}
// KMIP requires both server and client certificates, we store the certificate under the host name of the KMIP server
P6CLASSMETHODIMPL CKmipExample5::saveClientCertInStore( p6IKeystore* pKeystore, const P6WCHAR* pNamespace, const P6WCHAR* pName, const P6WCHAR* pFilePath )
{
p6ComPtr<p6ICert> cpNewCert;
P6WCHAR confPath[P6MAXPATH+2] = {0};
P6ERR err = eOk;
if (P6FAILED( err = p6GetDirectory( P6D_CONF, confPath, P6MAXPATH, NULL ))) return err;
if (P6FAILED( err = m_cpStr->wstrlcat( confPath, P6CNTOF(confPath), P6TEXT("/"), NULL ))) return err;
if (P6FAILED( err = m_cpStr->wstrlcat( confPath, P6CNTOF(confPath), pFilePath, NULL ))) return err;
if (P6SUCCEEDED( err = loadCertificateFromFile( confPath, cpNewCert.addressof() )))
{
err = pKeystore->setCertificate( pNamespace, pName, cpNewCert, NULL );
}
return err;
}
// Load in the keys we need to connect to the KMIP server into our new store, we store the private key under the host name of the KMIP server
P6CLASSMETHODIMPL CKmipExample5::savePrivKeyInStore( p6IKeystore* pKeystore, const P6WCHAR* pNamespace, const P6WCHAR* pName, const P6WCHAR* pFilePath, P6UINT32 keySize )
{
P6WCHAR confPath[P6MAXPATH+2] = {0};
P6ERR err = eOk;
if (P6FAILED( err = p6GetDirectory( P6D_CONF, confPath, P6MAXPATH, NULL ))) return err;
if (P6FAILED( err = m_cpStr->wstrlcat( confPath, P6CNTOF(confPath), P6TEXT("/"), NULL ))) return err;
if (P6FAILED( err = m_cpStr->wstrlcat( confPath, P6CNTOF(confPath), pFilePath, NULL ))) return err;
if (P6SUCCEEDED( err = loadKeyFromFile( confPath, keySize, cpNewKey.addressof() )))
{
err = pKeystore->setKey( pNamespace, pName, cpNewKey, NULL, 0, NULL );
}
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.
//
P6CLASSMETHODIMPL CKmipExample5::createKeystore( const P6WCHAR* pKeystoreName, const P6WCHAR* rootPEM, const P6WCHAR* certPEM, const P6WCHAR* privPEM, P6UINT32 privSize, p6IKeystoreInit** pInit, p6IKeystore** pKeystore )
{
P6ERR err = eOk;
*pInit = NULL;
*pKeystore = NULL;
// Create the keystore and fill it with vendor provided SSL certificates
if (P6FAILED( err = p6CreateInstance( NULL, CID_p6Keystore, VALIDATEIF( p6IKeystoreInit, pInit )))) return err;
err = (*pInit)->queryInterface( VALIDATEIF( p6IKeystore, pKeystore ));
if (P6FAILED( err = (*pInit)->initialize( P6KEYSTORE_NOFLAGS, m_cpCrypto, SH_SHA256, m_cpSignKey )))
{
if (NULL != (*pKeystore)) (*pKeystore)->release();
(*pKeystore) = NULL;
(*pInit)->release();
(*pInit) = NULL;
return err;
}
if (P6FAILED( err = (*pInit)->openSigned( NULL, pKeystoreName )))
{
if (NULL != (*pKeystore)) (*pKeystore)->release();
(*pKeystore) = NULL;
(*pInit)->release();
(*pInit) = NULL;
return err;
}
if (P6FAILED( err = saveRootCertInStore( (*pKeystore), P6TEXT("p6r.trustedroot"), rootPEM ))) return err;
if (P6FAILED( err = saveClientCertInStore( (*pKeystore), P6TEXT("p6r.clientauth"), m_pHostName, certPEM ))) return err;
if (P6FAILED( err = savePrivKeyInStore( (*pKeystore), P6TEXT("p6r.clientauth"), m_pHostName, privPEM, privSize ))) return err;
return eOk;
}
// Key generation requires an entropy source
P6CLASSMETHODIMPL CKmipExample5::getRNG( p6IRandom** ppRandom )
{
P6ERR err = eOk;
p6ComPtr<p6IRunningIface> cpRIT( IID_p6IRunningIface, &err );
if (P6SUCCEEDED( err = p6CreateCryptoInstance( CID_p6EntropySource, VALIDATECOMPTR( p6IEntropySource, cpSource ))))
{
if (P6SUCCEEDED( err = cpSource->initialize( P6ENTROPY_HIGH )))
{
if (P6SUCCEEDED( err = p6CreateCryptoInstance( CID_p6Random, VALIDATECOMPTR( p6IRandomInit, cpInit ))))
{
if (P6SUCCEEDED( err = cpInit->initialize( P6RAND_NOFLAGS, cpSource ))) {
err = cpInit.queryInterface( VALIDATEIF( p6IRandom, ppRandom ));
}
}
}
}
return err;
}
// Replace the host name of "fqdn.com" to the fully qualified domain name of the server you wish to connect to.
P6R::P6ERR CKmipExample5::initialize()
{
P6ERR err = eOk;
P6WCHAR dbPath[P6MAXPATH+20] = {0};
if (P6FAILED( err = p6GetRuntimeIface (VALIDATECOMPTR( p6ISafeString, m_cpStr )))) return err;
if (P6FAILED( err = p6CreateInstance(NULL, CID_p6Dir, VALIDATECOMPTR(p6IDir, cpDir)))) return err;
if (P6FAILED( err = cpDir->initialize())) return err;
if (P6FAILED( err = getRNG( m_cpRandom.addressof()))) return err;
// -> 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
//
m_port = 5696;
m_compatMask = 0;
if (P6FAILED( err = m_cpStr->wstrdup( P6TEXT("fqdn.com"), &m_pHostName ))) return err;
// -> create the keys required to encrypt the contents of the keystore
if (P6SUCCEEDED( err = getIGenKeys( cpGenKey.addressof() )))
{
err = cpGenKey->genSymmetricKey( m_cpSignKey.addressof(), 256, P6FALSE );
if (P6SUCCEEDED( err )) {
err = cpGenKey->genSymmetricKey( cpKey.addressof(), 256, P6FALSE );
}
}
if (P6SUCCEEDED( err )) err = p6CreateCryptoInstance( CID_p6SymmetricCrypto, VALIDATECOMPTR( p6ISymmetricCrypto, m_cpCrypto ));
if (P6SUCCEEDED( err )) err = m_cpCrypto->initialize( P6SYM_NOPADDING, CIPHER_AES_CFB );
if (P6SUCCEEDED( err )) err = m_cpCrypto->setKey( cpKey );
// -> initialize the keystore with keys provided to us by the server vendor
dbPath[0] = P6CHAR('\0');
if (P6FAILED( err = p6GetDirectory( P6D_DATA, dbPath, P6MAXPATH, NULL ))) return err;
if (P6FAILED( err = m_cpStr->wstrlcat( dbPath, P6CNTOF(dbPath), P6TEXT("/db/KMIP12_keystore"), NULL ))) return err;
cpDir->unlink( dbPath );
dbPath[0] = P6CHAR('\0');
if (P6FAILED( err = p6GetDirectory( P6D_DATA, dbPath, P6MAXPATH, NULL ))) return err;
if (P6FAILED( err = m_cpStr->wstrlcat( dbPath, P6CNTOF(dbPath), P6TEXT("/db/KMIP12_keystore.sig"), NULL ))) return err;
cpDir->unlink( dbPath );
err = createKeystore( P6TEXT("KMIP12_keystore"), P6TEXT("RootCert.pem"), P6TEXT("ClientCert.pem"), P6TEXT("ClientPrivate.pem"), 2048, m_cpStoreInit.addressof(), m_cpKeystore.addressof() );
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).
//
P6CLASSMETHODIMPL CKmipExample5::setPreferences( P6KMIP_PREF* pPrefs, P6WCHAR* pLogDir, P6UINT16 asynchronous, P6UINT32 privateKeyEncoding, P6UINT32 publicKeyEncoding,
P6UINT32 symmetricKeyEncoding, P6UINT32 maxBufferSize, P6UINT32 connectTimeout, P6UINT32 sendTimeout, P6UINT32 receiveTimeout,
P6UINT32 initialBufCount, P6UINT32 growBufsBy )
{
m_cpStr->setMem( 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
//
P6CLASSMETHODIMPL CKmipExample5::createSession( p6IKMIPClient* pClient, P6BOOL bWithCredentials )
{
P6KMIP_CREDENTIAL credential;
P6ERR err = eOk;
// -> integration testing setups are not production so QuintessenceLabs has a non-secure setup
if (P6FAILED( err = pClient->setSSLOptions( NULL, (P6SSF_METHOD_TLS1 | P6SSF_SECURE_CLIENT | P6SSF_SECURE_CLIENT_AUTH | P6SSF_LOG_X509SUBJECTLOOKUPS | P6SSF_VRFY_DISABLEHOSTMATCH)))) return err;
m_cpStr->setMem( &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->open( 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)
P6CLASSMETHODIMPL CKmipExample5::extractUniqueId( p6IKMIPStr* pEnum, P6NCSTR* pUniqueId )
{
P6CHAR* pGUID = NULL;
P6NCSTR buffer = { NULL, 0 };
P6ERR err = eOk;
pUniqueId->pString = NULL;
pUniqueId->length = 0;
err = pEnum->reset();
err = pEnum->next( &buffer );
if ( 0 < buffer.length )
{
if (NULL == (pGUID = new(std::nothrow) P6CHAR[buffer.length + 2])) return eNoMemory;
pGUID[0] = 0;
buffer.pString = pGUID;
buffer.length += 2;
if (P6FAILED( err = pEnum->next( &buffer ))) return err;
pUniqueId->pString = buffer.pString;
pUniqueId->length = buffer.length;
}
else err = eFail;
return err;
}
// Verify the string returned in pUniqueId matches that in the id parameter
P6R::P6BOOL CKmipExample5::isEqualId( p6IKMIPStr* pUniqueId, P6NCSTR id )
{
P6NCSTR enumStr = {NULL, 0};
P6INT32 match = -1;
P6ERR err = eOk;
if (NULL != pUniqueId)
{
if (P6FAILED( err = extractUniqueId( pUniqueId, &enumStr ))) return err;
if (enumStr.length == id.length)
{
err = m_cpStr->strcmp( enumStr.pString, id.pString, id.length, &match );
delete [] enumStr.pString;
}
}
return (0 == match);
}
// If a key is already in use or its state is "ACTIVE" then KMIP requires us to first revoke it before we can destroy it.
//
P6CLASSMETHODIMPL CKmipExample5::revokeAnddestroyObject( p6IKMIPClient* pClient, P6NCSTR objectId, P6UINT32 code )
{
P6KMIP_RESULT resultCodes;
p6IKMIPStr* pUniqueId = NULL;
P6BOOL bMatch = P6FALSE;
P6ERR err = eOk;
if (NULL != objectId.pString)
{
m_cpStr->setMem( &resultCodes, 0, sizeof( P6KMIP_RESULT ));
m_cpStr->setMem( &reason, 0, sizeof( P6KMIP_REVOCATION ));
reason.reasonCode = code;
err = pClient->revokeAndDestroyObject( objectId, reason, NULL, NULL, &pUniqueId, &resultCodes );
if ( P6FAILED( err )) {
printf("\ncall to revokeAndDestroyObject has failed %x\n", err );
}
else if (KMIP_RESULT_SUCCESS != resultCodes.resultStatus) {
printf("\nKMIP server returned an error - revoke and destroy object\n");
}
// -> KMIP server returns the unique id of the key it revokes so if we want we can verify it here or not
if (NULL != pUniqueId)
{
bMatch = isEqualId( pUniqueId, objectId );
if (!bMatch) {
printf("\nKMIP server to revoke object with wrong object uniqueId\n");
}
}
delete [] objectId.pString;
}
return err;
}
// When trying to destroy a key this can fail if the key is in an active state. Then we must retry first revoking the key.
//
P6CLASSMETHODIMPL CKmipExample5::destroyObject( p6IKMIPClient* pClient, P6NCSTR objectId, P6BOOL bFree )
{
P6KMIP_RESULT resultCodes;
p6IKMIPStr* pUniqueId = NULL;
P6BOOL bMatch = P6FALSE;
P6ERR err = eOk;
if (NULL != objectId.pString)
{
m_cpStr->setMem( &resultCodes, 0, sizeof( P6KMIP_RESULT ));
err = pClient->destroyObject( objectId, NULL, &pUniqueId, &resultCodes );
if ( P6FAILED( err )) {
printf("\ncall to destroyObject has failed %x\n", err );
}
else if (KMIP_RESULT_SUCCESS != resultCodes.resultStatus) {
printf("\nKMIP server returned an error - destroy object\n");
}
bMatch = isEqualId( pUniqueId, objectId );
if (!bMatch) {
printf("\nKMIP server to destroy object with wrong object uniqueId\n");
}
if (bFree) delete [] objectId.pString;
// -> did we fail trying to destroy the object?
if (KMIP_RESULT_SUCCESS != resultCodes.resultStatus) return eFail;
}
return err;
}
// Locate object (i.e., a generalized search) operation here is just searching for all objects
// of a specific type (e.g., public key, certificate).
//
P6CLASSMETHODIMPL CKmipExample5::locateAndFree( p6IKMIPClient* pClient, P6UINT32 objectType )
{
P6KMIP_RESULT resultCodes;
P6KMIP_LOCATEPARAMS locateParams;
P6KMIP_ATTRIBUTE attributeList[6];
P6CHAR* pGUID = NULL;
P6NCSTR buffer = { NULL, 0 };
p6IKMIPStr* pUniqueId = NULL;
P6UINT32 number = 0;
P6BOOL bDone = P6FALSE;
P6ERR err = eOk;
m_cpStr->setMem( &resultCodes, 0, sizeof( P6KMIP_RESULT ));
m_cpStr->setMem( &locateParams, 0, sizeof( P6KMIP_LOCATEPARAMS ));
attributeList[0].type = KMIP_ATTRIB_OBJECTTYPE;
attributeList[0].index = 0;
attributeList[0].value.objectType = objectType;
locateParams.attribCount = 1;
locateParams.pAttributeList = attributeList;
err = pClient->locateObject( locateParams, &pUniqueId, &resultCodes );
// -> there can be more than one item found, we return an enumerator to deal with that
// -> here a "string" enumerator is returned, where the strings are unique identifiers (i.e., GUIDs of some format)
if ( P6SUCCEEDED( err ) && NULL != pUniqueId )
{
err = pUniqueId->reset();
while( P6SUCCEEDED( err ) && !bDone )
{
// -> each item in a string enumerator can have a different length
err = pUniqueId->count( &number );
err = pUniqueId->next( &buffer );
if (NULL == (pGUID = new(std::nothrow) P6CHAR[buffer.length + 2])) return eNoMemory;
pGUID[0] = 0;
buffer.pString = pGUID;
buffer.length += 2;
if (P6SUCCEEDED( err = pUniqueId->next( &buffer )))
{
//printf( "\nObject UniqueId [%s] %d, %d [%d]\n", buffer.pString, buffer.length, i++, number );
switch ( objectType ) {
if ( P6FAILED( err = destroyObject( pClient, buffer, P6FALSE )))
err = revokeAnddestroyObject( pClient, buffer, KMIP_REVOC_UNSPECIFIED );
else delete [] buffer.pString;
break;
default:
err = destroyObject( pClient, buffer, P6TRUE );
break;
}
}
else {
bDone = P6TRUE;
}
buffer.pString = NULL;
buffer.length = 0;
}
pUniqueId->release();
}
return eOk;
}
// For testing purposes sometimes we leave keys/certificates/etc behind on the KMIP server.
// This example shows how to clear all managed objects off of a KMIP server.
// Main client function
//
P6CLASSMETHODIMPL CKmipExample5::run( p6IDataStream *pStreamDebug )
{
P6KMIP_PREF preferences;
P6ERR err = eOk;
// [1] Initialize, "CLEAN_UP" directory created in the configured log directory to hold all logs for this example
//
if (P6FAILED( err = p6CreateInstance( NULL, CID_p6KMIPClient, VALIDATECOMPTR( p6IKMIPClient, cpClient )))) return err;
setPreferences( &preferences, P6TEXT("CLEAN_UP"), 0, 0, 0, 0, 5000, 2000, 2000, 120000, 2, 2 );
err = cpClient->initialize( (P6KMIPFLG_TRACE_MSGS | P6KMIPFLG_TRACE_FORMATKMIPXML), m_cpKeystore, preferences );
// [2] Open a connection to the KMIP server via SSL
if (P6FAILED( err = createSession( cpClient, P6FALSE ))) return err;
// [3] Search and free for each type of managed object that can reside on a KMIP server
err = locateAndFree( cpClient, KMIP_OBJECT_CERTIFICATE );
err = locateAndFree( cpClient, KMIP_OBJECT_SYMMETRICKEY );
err = locateAndFree( cpClient, KMIP_OBJECT_PUBLICKEY );
err = locateAndFree( cpClient, KMIP_OBJECT_PRIVATEKEY );
err = locateAndFree( cpClient, KMIP_OBJECT_SPLITKEY );
err = locateAndFree( cpClient, KMIP_OBJECT_TEMPLATE );
err = locateAndFree( cpClient, KMIP_OBJECT_SECRETDATA );
err = locateAndFree( cpClient, KMIP_OBJECT_OPAQUE );
err = locateAndFree( cpClient, KMIP_OBJECT_PGPKEY );
return cpClient->close();
}
P6VOID KMIP_CleanUp( p6IDataStream* pDataStream )
{
P6ERR err = eOk;
CKmipExample5 example;
P6CHAR szTmp[32];
if (P6SUCCEEDED(err = example.initialize())) {
err = example.run(pDataStream);
}
printf( "KMIP client result: [ %s ]\n", p6ErrToStr(err, &szTmp[0], P6CHARCNT(szTmp)) );
}
} // namespace
// p6InitializeLoader() must be called before anything else can run.
//
int main(int argc,char *argv[])
{
P6ERR err = eOk;
if ( P6SUCCEEDED( err = P6EXAMPLES::CConsoleStream::createInstance( NULL, VALIDATECOMPTR( p6IDataStream, cpDataStream ))))
{
if ( P6SUCCEEDED( err = p6InitializeLoader( cpDataStream, 9, P6SCLF_ALLLOG )))
{
KMIP_CleanUp( cpDataStream );
}
else printf("ERROR: Failed to initialize the loader [ %x ]\n", err );
}
else printf( "ERROR: Failed to create CConsoleStream [ %x ]\n", err );
return err;
}