@@ -150,6 +150,62 @@ read_file_and_null_terminate (const char *filename, size_t *out_len)
150150}
151151
152152
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+
153209PCCERT_CONTEXT
154210mongoc_secure_channel_setup_certificate_from_file (const char * filename )
155211{
@@ -162,9 +218,11 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
162218 LPBYTE encoded_cert = NULL ;
163219 const char * pem_public ;
164220 const char * pem_private ;
165- LPBYTE blob_private = NULL ;
166221 PCCERT_CONTEXT cert = NULL ;
222+ LPBYTE blob_private = NULL ;
167223 DWORD blob_private_len = 0 ;
224+ LPBYTE blob_private_rsa = NULL ;
225+ DWORD blob_private_rsa_len = 0 ;
168226 DWORD encoded_private_len = 0 ;
169227 LPBYTE encoded_private = NULL ;
170228
@@ -186,16 +244,6 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
186244 goto fail ;
187245 }
188246
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-
199247 encoded_cert = decode_pem_base64 (pem_public , & encoded_cert_len , "public key" , filename );
200248 if (!encoded_cert ) {
201249 goto fail ;
@@ -209,43 +257,47 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
209257 goto fail ;
210258 }
211259
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+ }
218265
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+ }
235276
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 );
249301 goto fail ;
250302 }
251303
@@ -266,12 +318,12 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
266318 HCRYPTKEY hKey ;
267319 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa380207%28v=vs.85%29.aspx
268320 */
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 */
275327 if (!success ) {
276328 char * msg = mongoc_winerr_to_string (GetLastError ());
277329 MONGOC_ERROR ("CryptImportKey for private key failed: %s" , msg );
@@ -309,6 +361,11 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
309361 bson_free (encoded_private );
310362 }
311363
364+ if (blob_private_rsa ) {
365+ SecureZeroMemory (blob_private_rsa , blob_private_rsa_len );
366+ bson_free (blob_private_rsa );
367+ }
368+
312369 if (blob_private ) {
313370 SecureZeroMemory (blob_private , blob_private_len );
314371 bson_free (blob_private );
0 commit comments