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