@@ -149,6 +149,62 @@ read_file_and_null_terminate (const char *filename, size_t *out_len)
149149}
150150
151151
152+ // `decode_object` decodes a cryptographic object from a blob.
153+ // Returns NULL on error.
154+ static LPBYTE
155+ decode_object (const char * structType ,
156+ const LPBYTE data ,
157+ DWORD data_len ,
158+ DWORD * out_len ,
159+ const char * descriptor ,
160+ const char * filename )
161+ {
162+ BSON_ASSERT_PARAM (structType );
163+ BSON_ASSERT_PARAM (data );
164+ BSON_ASSERT_PARAM (structType );
165+ BSON_ASSERT_PARAM (out_len );
166+ BSON_ASSERT_PARAM (descriptor );
167+ BSON_ASSERT_PARAM (filename );
168+ // Get needed output length:
169+ if (!CryptDecodeObjectEx (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING , /* dwCertEncodingType */
170+ structType , /* lpszStructType */
171+ data , /* pbEncoded */
172+ data_len , /* cbEncoded */
173+ 0 , /* dwFlags */
174+ NULL , /* pDecodePara */
175+ NULL , /* pvStructInfo */
176+ out_len /* pcbStructInfo */
177+ )) {
178+ char * msg = mongoc_winerr_to_string (GetLastError ());
179+ MONGOC_ERROR ("Failed to decode %s from '%s': %s" , descriptor , filename , msg );
180+ bson_free (msg );
181+ return NULL ;
182+ }
183+
184+ if (* out_len == 0 ) {
185+ return NULL ;
186+ }
187+ LPBYTE out = (LPBYTE ) bson_malloc (* out_len );
188+
189+ if (!CryptDecodeObjectEx (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING , /* dwCertEncodingType */
190+ structType , /* lpszStructType */
191+ data , /* pbEncoded */
192+ data_len , /* cbEncoded */
193+ 0 , /* dwFlags */
194+ NULL , /* pDecodePara */
195+ out , /* pvStructInfo */
196+ out_len /* pcbStructInfo */
197+ )) {
198+ char * msg = mongoc_winerr_to_string (GetLastError ());
199+ MONGOC_ERROR ("Failed to decode %s from '%s': %s" , descriptor , filename , msg );
200+ bson_free (msg );
201+ bson_free (out );
202+ return NULL ;
203+ }
204+
205+ return out ;
206+ }
207+
152208PCCERT_CONTEXT
153209mongoc_secure_channel_setup_certificate_from_file (const char * filename )
154210{
@@ -161,9 +217,11 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
161217 LPBYTE encoded_cert = NULL ;
162218 const char * pem_public ;
163219 const char * pem_private ;
164- LPBYTE blob_private = NULL ;
165220 PCCERT_CONTEXT cert = NULL ;
221+ LPBYTE blob_private = NULL ;
166222 DWORD blob_private_len = 0 ;
223+ LPBYTE blob_private_rsa = NULL ;
224+ DWORD blob_private_rsa_len = 0 ;
167225 DWORD encoded_private_len = 0 ;
168226 LPBYTE encoded_private = NULL ;
169227
@@ -185,16 +243,6 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
185243 goto fail ;
186244 }
187245
188- pem_private = strstr (pem , "-----BEGIN RSA PRIVATE KEY-----" );
189- if (!pem_private ) {
190- pem_private = strstr (pem , "-----BEGIN PRIVATE KEY-----" );
191- }
192-
193- if (!pem_private ) {
194- MONGOC_ERROR ("Can't find private key in '%s'" , filename );
195- goto fail ;
196- }
197-
198246 encoded_cert = decode_pem_base64 (pem_public , & encoded_cert_len , "public key" , filename );
199247 if (!encoded_cert ) {
200248 goto fail ;
@@ -208,43 +256,47 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
208256 goto fail ;
209257 }
210258
211- /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa380285%28v=vs.85%29.aspx
212- */
213- encoded_private = decode_pem_base64 (pem_private , & encoded_private_len , "private key" , filename );
214- if (!encoded_private ) {
215- goto fail ;
216- }
259+ if (NULL != (pem_private = strstr (pem , "-----BEGIN RSA PRIVATE KEY-----" ))) {
260+ encoded_private = decode_pem_base64 (pem_private , & encoded_private_len , "private key" , filename );
261+ if (!encoded_private ) {
262+ goto fail ;
263+ }
217264
218- /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa379912%28v=vs.85%29.aspx
219- */
220- success = CryptDecodeObjectEx (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING , /* dwCertEncodingType */
221- PKCS_RSA_PRIVATE_KEY , /* lpszStructType */
222- encoded_private , /* pbEncoded */
223- encoded_private_len , /* cbEncoded */
224- 0 , /* dwFlags */
225- NULL , /* pDecodePara */
226- NULL , /* pvStructInfo */
227- & blob_private_len ); /* pcbStructInfo */
228- if (!success ) {
229- char * msg = mongoc_winerr_to_string (GetLastError ());
230- MONGOC_ERROR ("Failed to parse private key. %s" , msg );
231- bson_free (msg );
232- goto fail ;
233- }
265+ blob_private_rsa = decode_object (
266+ PKCS_RSA_PRIVATE_KEY , encoded_private , encoded_private_len , & blob_private_rsa_len , "private key" , filename );
267+ if (!blob_private_rsa ) {
268+ goto fail ;
269+ }
270+ } else if (NULL != (pem_private = strstr (pem , "-----BEGIN PRIVATE KEY-----" ))) {
271+ encoded_private = decode_pem_base64 (pem_private , & encoded_private_len , "private key" , filename );
272+ if (!encoded_private ) {
273+ goto fail ;
274+ }
234275
235- blob_private = (LPBYTE ) bson_malloc0 (blob_private_len );
236- success = CryptDecodeObjectEx (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
237- PKCS_RSA_PRIVATE_KEY ,
238- encoded_private ,
239- encoded_private_len ,
240- 0 ,
241- NULL ,
242- blob_private ,
243- & blob_private_len );
244- if (!success ) {
245- char * msg = mongoc_winerr_to_string (GetLastError ());
246- MONGOC_ERROR ("Failed to parse private key: %s" , msg );
247- bson_free (msg );
276+ blob_private = decode_object (
277+ PKCS_PRIVATE_KEY_INFO , encoded_private , encoded_private_len , & blob_private_len , "private key" , filename );
278+ if (!blob_private ) {
279+ goto fail ;
280+ }
281+
282+ // Have PrivateKey. Get RSA key from it.
283+ CRYPT_PRIVATE_KEY_INFO * privateKeyInfo = (CRYPT_PRIVATE_KEY_INFO * ) blob_private ;
284+ if (strcmp (privateKeyInfo -> Algorithm .pszObjId , szOID_RSA_RSA ) != 0 ) {
285+ MONGOC_ERROR ("Non-RSA private keys are not supported" );
286+ goto fail ;
287+ }
288+
289+ blob_private_rsa = decode_object (PKCS_RSA_PRIVATE_KEY ,
290+ privateKeyInfo -> PrivateKey .pbData ,
291+ privateKeyInfo -> PrivateKey .cbData ,
292+ & blob_private_rsa_len ,
293+ "private key" ,
294+ filename );
295+ if (!blob_private_rsa ) {
296+ goto fail ;
297+ }
298+ } else {
299+ MONGOC_ERROR ("Can't find private key in '%s'" , filename );
248300 goto fail ;
249301 }
250302
@@ -265,12 +317,12 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
265317 HCRYPTKEY hKey ;
266318 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa380207%28v=vs.85%29.aspx
267319 */
268- success = CryptImportKey (provider , /* hProv */
269- blob_private , /* pbData */
270- blob_private_len , /* dwDataLen */
271- 0 , /* hPubKey */
272- 0 , /* dwFlags */
273- & hKey ); /* phKey, OUT */
320+ success = CryptImportKey (provider , /* hProv */
321+ blob_private_rsa , /* pbData */
322+ blob_private_rsa_len , /* dwDataLen */
323+ 0 , /* hPubKey */
324+ 0 , /* dwFlags */
325+ & hKey ); /* phKey, OUT */
274326 if (!success ) {
275327 char * msg = mongoc_winerr_to_string (GetLastError ());
276328 MONGOC_ERROR ("CryptImportKey for private key failed: %s" , msg );
@@ -308,6 +360,11 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
308360 bson_free (encoded_private );
309361 }
310362
363+ if (blob_private_rsa ) {
364+ SecureZeroMemory (blob_private_rsa , blob_private_rsa_len );
365+ bson_free (blob_private_rsa );
366+ }
367+
311368 if (blob_private ) {
312369 SecureZeroMemory (blob_private , blob_private_len );
313370 bson_free (blob_private );
0 commit comments