1*12720SWyllys.Ingersoll@Sun.COM /* 2*12720SWyllys.Ingersoll@Sun.COM * CDDL HEADER START 3*12720SWyllys.Ingersoll@Sun.COM * 4*12720SWyllys.Ingersoll@Sun.COM * The contents of this file are subject to the terms of the 5*12720SWyllys.Ingersoll@Sun.COM * Common Development and Distribution License (the "License"). 6*12720SWyllys.Ingersoll@Sun.COM * You may not use this file except in compliance with the License. 7*12720SWyllys.Ingersoll@Sun.COM * 8*12720SWyllys.Ingersoll@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*12720SWyllys.Ingersoll@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*12720SWyllys.Ingersoll@Sun.COM * See the License for the specific language governing permissions 11*12720SWyllys.Ingersoll@Sun.COM * and limitations under the License. 12*12720SWyllys.Ingersoll@Sun.COM * 13*12720SWyllys.Ingersoll@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*12720SWyllys.Ingersoll@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*12720SWyllys.Ingersoll@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*12720SWyllys.Ingersoll@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*12720SWyllys.Ingersoll@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*12720SWyllys.Ingersoll@Sun.COM * 19*12720SWyllys.Ingersoll@Sun.COM * CDDL HEADER END 20*12720SWyllys.Ingersoll@Sun.COM */ 21*12720SWyllys.Ingersoll@Sun.COM 22*12720SWyllys.Ingersoll@Sun.COM /* 23*12720SWyllys.Ingersoll@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24*12720SWyllys.Ingersoll@Sun.COM */ 25*12720SWyllys.Ingersoll@Sun.COM 26*12720SWyllys.Ingersoll@Sun.COM /** 27*12720SWyllys.Ingersoll@Sun.COM * \file KMSAgentPKICert.cpp 28*12720SWyllys.Ingersoll@Sun.COM * 29*12720SWyllys.Ingersoll@Sun.COM * This is an implementation of PKICommon.h CCertificate class. 30*12720SWyllys.Ingersoll@Sun.COM */ 31*12720SWyllys.Ingersoll@Sun.COM 32*12720SWyllys.Ingersoll@Sun.COM #include <stdio.h> 33*12720SWyllys.Ingersoll@Sun.COM #include <memory.h> 34*12720SWyllys.Ingersoll@Sun.COM #include <time.h> 35*12720SWyllys.Ingersoll@Sun.COM #include <string.h> 36*12720SWyllys.Ingersoll@Sun.COM 37*12720SWyllys.Ingersoll@Sun.COM #ifdef KMSUSERPKCS12 38*12720SWyllys.Ingersoll@Sun.COM #include <openssl/bio.h> 39*12720SWyllys.Ingersoll@Sun.COM #include <openssl/evp.h> 40*12720SWyllys.Ingersoll@Sun.COM #include <openssl/conf.h> 41*12720SWyllys.Ingersoll@Sun.COM #include <openssl/err.h> 42*12720SWyllys.Ingersoll@Sun.COM #include <openssl/asn1.h> 43*12720SWyllys.Ingersoll@Sun.COM #include <openssl/x509.h> 44*12720SWyllys.Ingersoll@Sun.COM #include <openssl/x509v3.h> 45*12720SWyllys.Ingersoll@Sun.COM #include <openssl/objects.h> 46*12720SWyllys.Ingersoll@Sun.COM #include <openssl/pem.h> 47*12720SWyllys.Ingersoll@Sun.COM #include <openssl/pkcs12.h> 48*12720SWyllys.Ingersoll@Sun.COM #endif 49*12720SWyllys.Ingersoll@Sun.COM 50*12720SWyllys.Ingersoll@Sun.COM #include "SYSCommon.h" 51*12720SWyllys.Ingersoll@Sun.COM #include "KMSAgentPKICommon.h" 52*12720SWyllys.Ingersoll@Sun.COM #include "KMSAgentPKIimpl.h" 53*12720SWyllys.Ingersoll@Sun.COM 54*12720SWyllys.Ingersoll@Sun.COM ///////////////////////////////////////////////////////////////////////// 55*12720SWyllys.Ingersoll@Sun.COM // CCertificate 56*12720SWyllys.Ingersoll@Sun.COM // 57*12720SWyllys.Ingersoll@Sun.COM CCertificate::CCertificate() 58*12720SWyllys.Ingersoll@Sun.COM { 59*12720SWyllys.Ingersoll@Sun.COM m_pCertImpl = InitializeCertImpl(); 60*12720SWyllys.Ingersoll@Sun.COM 61*12720SWyllys.Ingersoll@Sun.COM FATAL_ASSERT( m_pCertImpl != NULL ); 62*12720SWyllys.Ingersoll@Sun.COM } 63*12720SWyllys.Ingersoll@Sun.COM 64*12720SWyllys.Ingersoll@Sun.COM 65*12720SWyllys.Ingersoll@Sun.COM CCertificate::~CCertificate() 66*12720SWyllys.Ingersoll@Sun.COM { 67*12720SWyllys.Ingersoll@Sun.COM if ( m_pCertImpl != NULL ) 68*12720SWyllys.Ingersoll@Sun.COM { 69*12720SWyllys.Ingersoll@Sun.COM FinalizeCertImpl( m_pCertImpl ); 70*12720SWyllys.Ingersoll@Sun.COM } 71*12720SWyllys.Ingersoll@Sun.COM } 72*12720SWyllys.Ingersoll@Sun.COM 73*12720SWyllys.Ingersoll@Sun.COM /** 74*12720SWyllys.Ingersoll@Sun.COM * Save - This OVERLOADED method saves the Cert into a file 75*12720SWyllys.Ingersoll@Sun.COM * @param i_pcFileName - filename of file to save into 76*12720SWyllys.Ingersoll@Sun.COM * @param i_iFormat - IGNORED 77*12720SWyllys.Ingersoll@Sun.COM * 78*12720SWyllys.Ingersoll@Sun.COM * @returns bool - success (true = successful) 79*12720SWyllys.Ingersoll@Sun.COM */ 80*12720SWyllys.Ingersoll@Sun.COM bool CCertificate::Save( const char * const i_pcFileName, 81*12720SWyllys.Ingersoll@Sun.COM int i_iFormat ) 82*12720SWyllys.Ingersoll@Sun.COM { 83*12720SWyllys.Ingersoll@Sun.COM return SaveX509CertTofile( m_pCertImpl, i_pcFileName ); 84*12720SWyllys.Ingersoll@Sun.COM } 85*12720SWyllys.Ingersoll@Sun.COM 86*12720SWyllys.Ingersoll@Sun.COM /** 87*12720SWyllys.Ingersoll@Sun.COM * Save - This OVERLOADED method saves the Cert into a buffer 88*12720SWyllys.Ingersoll@Sun.COM * @param i_pcBuffer - buffer to save into 89*12720SWyllys.Ingersoll@Sun.COM * @param i_BufferLength - length of buffer to save 90*12720SWyllys.Ingersoll@Sun.COM * @param o_pActualLength - length of buffer saved 91*12720SWyllys.Ingersoll@Sun.COM * @param i_iFormat - IGNORED 92*12720SWyllys.Ingersoll@Sun.COM * 93*12720SWyllys.Ingersoll@Sun.COM * @returns bool - success (true = successful) 94*12720SWyllys.Ingersoll@Sun.COM */ 95*12720SWyllys.Ingersoll@Sun.COM bool CCertificate::Save( unsigned char * const i_pcBuffer, 96*12720SWyllys.Ingersoll@Sun.COM int i_iBufferLength, 97*12720SWyllys.Ingersoll@Sun.COM int * const o_pActualLength, 98*12720SWyllys.Ingersoll@Sun.COM int i_iFormat ) 99*12720SWyllys.Ingersoll@Sun.COM { 100*12720SWyllys.Ingersoll@Sun.COM return SaveX509CertToBuffer( m_pCertImpl, 101*12720SWyllys.Ingersoll@Sun.COM i_pcBuffer, 102*12720SWyllys.Ingersoll@Sun.COM i_iBufferLength, 103*12720SWyllys.Ingersoll@Sun.COM o_pActualLength ); 104*12720SWyllys.Ingersoll@Sun.COM } 105*12720SWyllys.Ingersoll@Sun.COM 106*12720SWyllys.Ingersoll@Sun.COM /** 107*12720SWyllys.Ingersoll@Sun.COM * Load 108*12720SWyllys.Ingersoll@Sun.COM * This OVERLOADED method loads the Cert from a FILE 109*12720SWyllys.Ingersoll@Sun.COM * @param i_pcFileName - name of file to load from 110*12720SWyllys.Ingersoll@Sun.COM * @param i_iFormat - IGNORED 111*12720SWyllys.Ingersoll@Sun.COM * 112*12720SWyllys.Ingersoll@Sun.COM * @returns bool - success (true = successful) 113*12720SWyllys.Ingersoll@Sun.COM */ 114*12720SWyllys.Ingersoll@Sun.COM 115*12720SWyllys.Ingersoll@Sun.COM bool CCertificate::Load( const char * const i_pcFileName, 116*12720SWyllys.Ingersoll@Sun.COM int i_iFormat ) 117*12720SWyllys.Ingersoll@Sun.COM { 118*12720SWyllys.Ingersoll@Sun.COM return LoadX509CertFromFile( m_pCertImpl, i_pcFileName ); 119*12720SWyllys.Ingersoll@Sun.COM } 120*12720SWyllys.Ingersoll@Sun.COM 121*12720SWyllys.Ingersoll@Sun.COM /** 122*12720SWyllys.Ingersoll@Sun.COM * Load 123*12720SWyllys.Ingersoll@Sun.COM * This OVERLOADED method loads the Cert from a buffer 124*12720SWyllys.Ingersoll@Sun.COM * @param i_pcBuffer - buffer to load from 125*12720SWyllys.Ingersoll@Sun.COM * @param i_iLength - amount to load from buffer 126*12720SWyllys.Ingersoll@Sun.COM * @param i_iFormat - IGNORED 127*12720SWyllys.Ingersoll@Sun.COM * 128*12720SWyllys.Ingersoll@Sun.COM * @returns bool - success (true = successful) 129*12720SWyllys.Ingersoll@Sun.COM */ 130*12720SWyllys.Ingersoll@Sun.COM bool CCertificate::Load( unsigned char * const i_pcBuffer, 131*12720SWyllys.Ingersoll@Sun.COM int i_iLength, 132*12720SWyllys.Ingersoll@Sun.COM int i_iFormat ) 133*12720SWyllys.Ingersoll@Sun.COM { 134*12720SWyllys.Ingersoll@Sun.COM return LoadX509CertFromBuffer( m_pCertImpl, i_pcBuffer, i_iLength ); 135*12720SWyllys.Ingersoll@Sun.COM } 136*12720SWyllys.Ingersoll@Sun.COM 137*12720SWyllys.Ingersoll@Sun.COM /** 138*12720SWyllys.Ingersoll@Sun.COM * Dump 139*12720SWyllys.Ingersoll@Sun.COM * dump the readable format to standard output 140*12720SWyllys.Ingersoll@Sun.COM * @returns bool - success (true = successful) 141*12720SWyllys.Ingersoll@Sun.COM */ 142*12720SWyllys.Ingersoll@Sun.COM bool CCertificate::Dump() 143*12720SWyllys.Ingersoll@Sun.COM { 144*12720SWyllys.Ingersoll@Sun.COM return PrintX509Cert( m_pCertImpl ); 145*12720SWyllys.Ingersoll@Sun.COM } 146*12720SWyllys.Ingersoll@Sun.COM 147*12720SWyllys.Ingersoll@Sun.COM #ifdef KMSUSERPKCS12 148*12720SWyllys.Ingersoll@Sun.COM bool 149*12720SWyllys.Ingersoll@Sun.COM CCertificate::LoadPKCS12CertAndKey( 150*12720SWyllys.Ingersoll@Sun.COM char *filename, 151*12720SWyllys.Ingersoll@Sun.COM int i_iFormat, 152*12720SWyllys.Ingersoll@Sun.COM CPrivateKey *i_pPrivateKey, 153*12720SWyllys.Ingersoll@Sun.COM char *i_pPassphrase) 154*12720SWyllys.Ingersoll@Sun.COM { 155*12720SWyllys.Ingersoll@Sun.COM BIO *pFileBio= NULL; 156*12720SWyllys.Ingersoll@Sun.COM X509 *pRequest =NULL; 157*12720SWyllys.Ingersoll@Sun.COM 158*12720SWyllys.Ingersoll@Sun.COM pFileBio = BIO_new(BIO_s_file()); 159*12720SWyllys.Ingersoll@Sun.COM if (pFileBio == NULL) 160*12720SWyllys.Ingersoll@Sun.COM return false; 161*12720SWyllys.Ingersoll@Sun.COM if (!BIO_read_filename(pFileBio, filename)) { 162*12720SWyllys.Ingersoll@Sun.COM BIO_free(pFileBio); 163*12720SWyllys.Ingersoll@Sun.COM return (false); 164*12720SWyllys.Ingersoll@Sun.COM } 165*12720SWyllys.Ingersoll@Sun.COM 166*12720SWyllys.Ingersoll@Sun.COM switch( i_iFormat ) { 167*12720SWyllys.Ingersoll@Sun.COM case FILE_FORMAT_DER: 168*12720SWyllys.Ingersoll@Sun.COM 169*12720SWyllys.Ingersoll@Sun.COM pRequest=d2i_X509_bio(pFileBio, NULL); 170*12720SWyllys.Ingersoll@Sun.COM if (pRequest == NULL) { 171*12720SWyllys.Ingersoll@Sun.COM // fixme: log: invalid certificate format 172*12720SWyllys.Ingersoll@Sun.COM return false; 173*12720SWyllys.Ingersoll@Sun.COM } 174*12720SWyllys.Ingersoll@Sun.COM break; 175*12720SWyllys.Ingersoll@Sun.COM 176*12720SWyllys.Ingersoll@Sun.COM case FILE_FORMAT_PEM: 177*12720SWyllys.Ingersoll@Sun.COM 178*12720SWyllys.Ingersoll@Sun.COM pRequest=PEM_read_bio_X509(pFileBio, NULL, NULL, NULL); 179*12720SWyllys.Ingersoll@Sun.COM if (pRequest == NULL) { 180*12720SWyllys.Ingersoll@Sun.COM // fixme: log: invalid certificate format 181*12720SWyllys.Ingersoll@Sun.COM return false; 182*12720SWyllys.Ingersoll@Sun.COM } 183*12720SWyllys.Ingersoll@Sun.COM break; 184*12720SWyllys.Ingersoll@Sun.COM 185*12720SWyllys.Ingersoll@Sun.COM case FILE_FORMAT_PKCS12: 186*12720SWyllys.Ingersoll@Sun.COM PKCS12* pPKCS12Request = d2i_PKCS12_bio(pFileBio, NULL); 187*12720SWyllys.Ingersoll@Sun.COM if (pPKCS12Request == NULL) { 188*12720SWyllys.Ingersoll@Sun.COM // fixme: log: invalid certificate format 189*12720SWyllys.Ingersoll@Sun.COM return false; 190*12720SWyllys.Ingersoll@Sun.COM } 191*12720SWyllys.Ingersoll@Sun.COM 192*12720SWyllys.Ingersoll@Sun.COM // convert PKCS12 to X509 193*12720SWyllys.Ingersoll@Sun.COM EVP_PKEY *pKeyTemp = NULL; 194*12720SWyllys.Ingersoll@Sun.COM if (!PKCS12_parse(pPKCS12Request, i_pPassphrase, 195*12720SWyllys.Ingersoll@Sun.COM &pKeyTemp, &pRequest, NULL)) { 196*12720SWyllys.Ingersoll@Sun.COM // fixme: log: invalid certificate format or passphrase 197*12720SWyllys.Ingersoll@Sun.COM PKCS12_free(pPKCS12Request); 198*12720SWyllys.Ingersoll@Sun.COM return false; 199*12720SWyllys.Ingersoll@Sun.COM } 200*12720SWyllys.Ingersoll@Sun.COM 201*12720SWyllys.Ingersoll@Sun.COM if (pKeyTemp && i_pPrivateKey) { 202*12720SWyllys.Ingersoll@Sun.COM i_pPrivateKey->SetNative((void *)pKeyTemp); 203*12720SWyllys.Ingersoll@Sun.COM } else if (pKeyTemp) 204*12720SWyllys.Ingersoll@Sun.COM EVP_PKEY_free(pKeyTemp); 205*12720SWyllys.Ingersoll@Sun.COM 206*12720SWyllys.Ingersoll@Sun.COM PKCS12_free(pPKCS12Request); 207*12720SWyllys.Ingersoll@Sun.COM break; 208*12720SWyllys.Ingersoll@Sun.COM } 209*12720SWyllys.Ingersoll@Sun.COM if (pRequest != NULL) { 210*12720SWyllys.Ingersoll@Sun.COM SetCert(m_pCertImpl, (void *)pRequest); 211*12720SWyllys.Ingersoll@Sun.COM } 212*12720SWyllys.Ingersoll@Sun.COM 213*12720SWyllys.Ingersoll@Sun.COM return (true); 214*12720SWyllys.Ingersoll@Sun.COM } 215*12720SWyllys.Ingersoll@Sun.COM 216*12720SWyllys.Ingersoll@Sun.COM void * 217*12720SWyllys.Ingersoll@Sun.COM CCertificate::SaveCertToPKCS12MemoryBIO( 218*12720SWyllys.Ingersoll@Sun.COM CPrivateKey* i_pPrivateKey, 219*12720SWyllys.Ingersoll@Sun.COM char *i_sPassphrase) 220*12720SWyllys.Ingersoll@Sun.COM { 221*12720SWyllys.Ingersoll@Sun.COM BIO *pMemBio = NULL; 222*12720SWyllys.Ingersoll@Sun.COM int iReturn; 223*12720SWyllys.Ingersoll@Sun.COM 224*12720SWyllys.Ingersoll@Sun.COM // create memory BIO 225*12720SWyllys.Ingersoll@Sun.COM pMemBio = BIO_new(BIO_s_mem()); 226*12720SWyllys.Ingersoll@Sun.COM 227*12720SWyllys.Ingersoll@Sun.COM if(pMemBio == NULL) 228*12720SWyllys.Ingersoll@Sun.COM { 229*12720SWyllys.Ingersoll@Sun.COM //fixme: log -- no memory 230*12720SWyllys.Ingersoll@Sun.COM return NULL; 231*12720SWyllys.Ingersoll@Sun.COM } 232*12720SWyllys.Ingersoll@Sun.COM 233*12720SWyllys.Ingersoll@Sun.COM PKCS12 *p12 = PKCS12_create(i_sPassphrase, 234*12720SWyllys.Ingersoll@Sun.COM NULL, 235*12720SWyllys.Ingersoll@Sun.COM (EVP_PKEY *)i_pPrivateKey->GetNative(), 236*12720SWyllys.Ingersoll@Sun.COM (X509 *)GetCert(m_pCertImpl), 237*12720SWyllys.Ingersoll@Sun.COM NULL, 238*12720SWyllys.Ingersoll@Sun.COM 0, 239*12720SWyllys.Ingersoll@Sun.COM 0, 240*12720SWyllys.Ingersoll@Sun.COM 0, 241*12720SWyllys.Ingersoll@Sun.COM 0, 242*12720SWyllys.Ingersoll@Sun.COM 0); 243*12720SWyllys.Ingersoll@Sun.COM if ( ! p12 ) 244*12720SWyllys.Ingersoll@Sun.COM { 245*12720SWyllys.Ingersoll@Sun.COM return NULL; 246*12720SWyllys.Ingersoll@Sun.COM } 247*12720SWyllys.Ingersoll@Sun.COM 248*12720SWyllys.Ingersoll@Sun.COM // now pMemBIO != NULL, remember to free it before exiting 249*12720SWyllys.Ingersoll@Sun.COM iReturn = i2d_PKCS12_bio(pMemBio, p12); 250*12720SWyllys.Ingersoll@Sun.COM 251*12720SWyllys.Ingersoll@Sun.COM if(!iReturn) // return 0: means error occurs 252*12720SWyllys.Ingersoll@Sun.COM { 253*12720SWyllys.Ingersoll@Sun.COM //fixme: log -- could not export private key 254*12720SWyllys.Ingersoll@Sun.COM BIO_free(pMemBio); 255*12720SWyllys.Ingersoll@Sun.COM return NULL; 256*12720SWyllys.Ingersoll@Sun.COM } 257*12720SWyllys.Ingersoll@Sun.COM 258*12720SWyllys.Ingersoll@Sun.COM return (void *)pMemBio; 259*12720SWyllys.Ingersoll@Sun.COM } 260*12720SWyllys.Ingersoll@Sun.COM 261*12720SWyllys.Ingersoll@Sun.COM bool 262*12720SWyllys.Ingersoll@Sun.COM CCertificate::SavePKCS12( 263*12720SWyllys.Ingersoll@Sun.COM unsigned char *i_pcBuffer, 264*12720SWyllys.Ingersoll@Sun.COM int i_iBufferLength, 265*12720SWyllys.Ingersoll@Sun.COM int *o_pActualLength, 266*12720SWyllys.Ingersoll@Sun.COM CPrivateKey* i_pPrivateKey, 267*12720SWyllys.Ingersoll@Sun.COM char* i_sPassphrase ) 268*12720SWyllys.Ingersoll@Sun.COM { 269*12720SWyllys.Ingersoll@Sun.COM BIO *pMemBio = NULL; 270*12720SWyllys.Ingersoll@Sun.COM char *pData = NULL; 271*12720SWyllys.Ingersoll@Sun.COM int iLength; 272*12720SWyllys.Ingersoll@Sun.COM 273*12720SWyllys.Ingersoll@Sun.COM // sanity check 274*12720SWyllys.Ingersoll@Sun.COM if(i_pcBuffer == NULL) return false; 275*12720SWyllys.Ingersoll@Sun.COM if(i_iBufferLength <= 0) return false; 276*12720SWyllys.Ingersoll@Sun.COM if(o_pActualLength == NULL) return false; 277*12720SWyllys.Ingersoll@Sun.COM 278*12720SWyllys.Ingersoll@Sun.COM // create memory BIO 279*12720SWyllys.Ingersoll@Sun.COM pMemBio = (BIO *)SaveCertToPKCS12MemoryBIO(i_pPrivateKey, i_sPassphrase); 280*12720SWyllys.Ingersoll@Sun.COM 281*12720SWyllys.Ingersoll@Sun.COM if(pMemBio == NULL) 282*12720SWyllys.Ingersoll@Sun.COM { 283*12720SWyllys.Ingersoll@Sun.COM //fixme: log -- no memory 284*12720SWyllys.Ingersoll@Sun.COM return false; 285*12720SWyllys.Ingersoll@Sun.COM } 286*12720SWyllys.Ingersoll@Sun.COM 287*12720SWyllys.Ingersoll@Sun.COM iLength = BIO_get_mem_data(pMemBio, &pData); 288*12720SWyllys.Ingersoll@Sun.COM 289*12720SWyllys.Ingersoll@Sun.COM // If the output buffer is a string, it needs to be NULL terminated 290*12720SWyllys.Ingersoll@Sun.COM // So always append a NULL to the output 291*12720SWyllys.Ingersoll@Sun.COM if(iLength + 1 > i_iBufferLength) 292*12720SWyllys.Ingersoll@Sun.COM { 293*12720SWyllys.Ingersoll@Sun.COM //fixme: log -- buffer too small 294*12720SWyllys.Ingersoll@Sun.COM BIO_free(pMemBio); 295*12720SWyllys.Ingersoll@Sun.COM return false; 296*12720SWyllys.Ingersoll@Sun.COM } 297*12720SWyllys.Ingersoll@Sun.COM // copy the data to given buffer 298*12720SWyllys.Ingersoll@Sun.COM memcpy(i_pcBuffer, pData, iLength); 299*12720SWyllys.Ingersoll@Sun.COM // NULL terminate the string 300*12720SWyllys.Ingersoll@Sun.COM i_pcBuffer[iLength] = '\0'; 301*12720SWyllys.Ingersoll@Sun.COM *o_pActualLength = iLength; 302*12720SWyllys.Ingersoll@Sun.COM 303*12720SWyllys.Ingersoll@Sun.COM // free memory 304*12720SWyllys.Ingersoll@Sun.COM BIO_free(pMemBio); 305*12720SWyllys.Ingersoll@Sun.COM 306*12720SWyllys.Ingersoll@Sun.COM return true; 307*12720SWyllys.Ingersoll@Sun.COM } 308*12720SWyllys.Ingersoll@Sun.COM #endif /* PKCS12 */ 309