@@ -150,6 +150,62 @@ read_file_and_null_terminate (const char *filename, size_t *out_len)
150
150
}
151
151
152
152
153
+ // `decode_object` decodes a cryptographic object from a blob.
154
+ // Returns NULL on error.
155
+ static LPBYTE
156
+ decode_object (const char * structType ,
157
+ const LPBYTE data ,
158
+ DWORD data_len ,
159
+ DWORD * out_len ,
160
+ const char * descriptor ,
161
+ const char * filename )
162
+ {
163
+ BSON_ASSERT_PARAM (structType );
164
+ BSON_ASSERT_PARAM (data );
165
+ BSON_ASSERT_PARAM (structType );
166
+ BSON_ASSERT_PARAM (out_len );
167
+ BSON_ASSERT_PARAM (descriptor );
168
+ BSON_ASSERT_PARAM (filename );
169
+ // Get needed output length:
170
+ if (!CryptDecodeObjectEx (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING , /* dwCertEncodingType */
171
+ structType , /* lpszStructType */
172
+ data , /* pbEncoded */
173
+ data_len , /* cbEncoded */
174
+ 0 , /* dwFlags */
175
+ NULL , /* pDecodePara */
176
+ NULL , /* pvStructInfo */
177
+ out_len /* pcbStructInfo */
178
+ )) {
179
+ char * msg = mongoc_winerr_to_string (GetLastError ());
180
+ MONGOC_ERROR ("Failed to decode %s from '%s': %s" , descriptor , filename , msg );
181
+ bson_free (msg );
182
+ return NULL ;
183
+ }
184
+
185
+ if (* out_len == 0 ) {
186
+ return NULL ;
187
+ }
188
+ LPBYTE out = (LPBYTE ) bson_malloc (* out_len );
189
+
190
+ if (!CryptDecodeObjectEx (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING , /* dwCertEncodingType */
191
+ structType , /* lpszStructType */
192
+ data , /* pbEncoded */
193
+ data_len , /* cbEncoded */
194
+ 0 , /* dwFlags */
195
+ NULL , /* pDecodePara */
196
+ out , /* pvStructInfo */
197
+ out_len /* pcbStructInfo */
198
+ )) {
199
+ char * msg = mongoc_winerr_to_string (GetLastError ());
200
+ MONGOC_ERROR ("Failed to decode %s from '%s': %s" , descriptor , filename , msg );
201
+ bson_free (msg );
202
+ bson_free (out );
203
+ return NULL ;
204
+ }
205
+
206
+ return out ;
207
+ }
208
+
153
209
PCCERT_CONTEXT
154
210
mongoc_secure_channel_setup_certificate_from_file (const char * filename )
155
211
{
@@ -162,9 +218,11 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
162
218
LPBYTE encoded_cert = NULL ;
163
219
const char * pem_public ;
164
220
const char * pem_private ;
165
- LPBYTE blob_private = NULL ;
166
221
PCCERT_CONTEXT cert = NULL ;
222
+ LPBYTE blob_private = NULL ;
167
223
DWORD blob_private_len = 0 ;
224
+ LPBYTE blob_private_rsa = NULL ;
225
+ DWORD blob_private_rsa_len = 0 ;
168
226
DWORD encoded_private_len = 0 ;
169
227
LPBYTE encoded_private = NULL ;
170
228
@@ -186,16 +244,6 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
186
244
goto fail ;
187
245
}
188
246
189
- pem_private = strstr (pem , "-----BEGIN RSA PRIVATE KEY-----" );
190
- if (!pem_private ) {
191
- pem_private = strstr (pem , "-----BEGIN PRIVATE KEY-----" );
192
- }
193
-
194
- if (!pem_private ) {
195
- MONGOC_ERROR ("Can't find private key in '%s'" , filename );
196
- goto fail ;
197
- }
198
-
199
247
encoded_cert = decode_pem_base64 (pem_public , & encoded_cert_len , "public key" , filename );
200
248
if (!encoded_cert ) {
201
249
goto fail ;
@@ -209,43 +257,47 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
209
257
goto fail ;
210
258
}
211
259
212
- /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa380285%28v=vs.85%29.aspx
213
- */
214
- encoded_private = decode_pem_base64 (pem_private , & encoded_private_len , "private key" , filename );
215
- if (!encoded_private ) {
216
- goto fail ;
217
- }
260
+ if (NULL != (pem_private = strstr (pem , "-----BEGIN RSA PRIVATE KEY-----" ))) {
261
+ encoded_private = decode_pem_base64 (pem_private , & encoded_private_len , "private key" , filename );
262
+ if (!encoded_private ) {
263
+ goto fail ;
264
+ }
218
265
219
- /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa379912%28v=vs.85%29.aspx
220
- */
221
- success = CryptDecodeObjectEx (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING , /* dwCertEncodingType */
222
- PKCS_RSA_PRIVATE_KEY , /* lpszStructType */
223
- encoded_private , /* pbEncoded */
224
- encoded_private_len , /* cbEncoded */
225
- 0 , /* dwFlags */
226
- NULL , /* pDecodePara */
227
- NULL , /* pvStructInfo */
228
- & blob_private_len ); /* pcbStructInfo */
229
- if (!success ) {
230
- char * msg = mongoc_winerr_to_string (GetLastError ());
231
- MONGOC_ERROR ("Failed to parse private key. %s" , msg );
232
- bson_free (msg );
233
- goto fail ;
234
- }
266
+ blob_private_rsa = decode_object (
267
+ PKCS_RSA_PRIVATE_KEY , encoded_private , encoded_private_len , & blob_private_rsa_len , "private key" , filename );
268
+ if (!blob_private_rsa ) {
269
+ goto fail ;
270
+ }
271
+ } else if (NULL != (pem_private = strstr (pem , "-----BEGIN PRIVATE KEY-----" ))) {
272
+ encoded_private = decode_pem_base64 (pem_private , & encoded_private_len , "private key" , filename );
273
+ if (!encoded_private ) {
274
+ goto fail ;
275
+ }
235
276
236
- blob_private = (LPBYTE ) bson_malloc0 (blob_private_len );
237
- success = CryptDecodeObjectEx (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
238
- PKCS_RSA_PRIVATE_KEY ,
239
- encoded_private ,
240
- encoded_private_len ,
241
- 0 ,
242
- NULL ,
243
- blob_private ,
244
- & blob_private_len );
245
- if (!success ) {
246
- char * msg = mongoc_winerr_to_string (GetLastError ());
247
- MONGOC_ERROR ("Failed to parse private key: %s" , msg );
248
- bson_free (msg );
277
+ blob_private = decode_object (
278
+ PKCS_PRIVATE_KEY_INFO , encoded_private , encoded_private_len , & blob_private_len , "private key" , filename );
279
+ if (!blob_private ) {
280
+ goto fail ;
281
+ }
282
+
283
+ // Have PrivateKey. Get RSA key from it.
284
+ CRYPT_PRIVATE_KEY_INFO * privateKeyInfo = (CRYPT_PRIVATE_KEY_INFO * ) blob_private ;
285
+ if (strcmp (privateKeyInfo -> Algorithm .pszObjId , szOID_RSA_RSA ) != 0 ) {
286
+ MONGOC_ERROR ("Non-RSA private keys are not supported" );
287
+ goto fail ;
288
+ }
289
+
290
+ blob_private_rsa = decode_object (PKCS_RSA_PRIVATE_KEY ,
291
+ privateKeyInfo -> PrivateKey .pbData ,
292
+ privateKeyInfo -> PrivateKey .cbData ,
293
+ & blob_private_rsa_len ,
294
+ "private key" ,
295
+ filename );
296
+ if (!blob_private_rsa ) {
297
+ goto fail ;
298
+ }
299
+ } else {
300
+ MONGOC_ERROR ("Can't find private key in '%s'" , filename );
249
301
goto fail ;
250
302
}
251
303
@@ -266,12 +318,12 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
266
318
HCRYPTKEY hKey ;
267
319
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa380207%28v=vs.85%29.aspx
268
320
*/
269
- success = CryptImportKey (provider , /* hProv */
270
- blob_private , /* pbData */
271
- blob_private_len , /* dwDataLen */
272
- 0 , /* hPubKey */
273
- 0 , /* dwFlags */
274
- & hKey ); /* phKey, OUT */
321
+ success = CryptImportKey (provider , /* hProv */
322
+ blob_private_rsa , /* pbData */
323
+ blob_private_rsa_len , /* dwDataLen */
324
+ 0 , /* hPubKey */
325
+ 0 , /* dwFlags */
326
+ & hKey ); /* phKey, OUT */
275
327
if (!success ) {
276
328
char * msg = mongoc_winerr_to_string (GetLastError ());
277
329
MONGOC_ERROR ("CryptImportKey for private key failed: %s" , msg );
@@ -309,6 +361,11 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
309
361
bson_free (encoded_private );
310
362
}
311
363
364
+ if (blob_private_rsa ) {
365
+ SecureZeroMemory (blob_private_rsa , blob_private_rsa_len );
366
+ bson_free (blob_private_rsa );
367
+ }
368
+
312
369
if (blob_private ) {
313
370
SecureZeroMemory (blob_private , blob_private_len );
314
371
bson_free (blob_private );
0 commit comments