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