[mini] Use C++ linker iff building C++ that needs the C++ runtime (#12266)
[mono-project.git] / mono / btls / btls-pkcs12.c
blob180b40760433d620546aef5e7b98d80ecb784d9f
1 //
2 // btls-pkcs12.c
3 // MonoBtls
4 //
5 // Created by Martin Baulig on 3/8/16.
6 // Copyright © 2016 Xamarin. All rights reserved.
7 //
9 #include "btls-pkcs12.h"
10 #include <openssl/pkcs12.h>
12 #ifdef WIN32
13 #include <windows.h>
14 #endif
16 struct MonoBtlsPkcs12 {
17 STACK_OF(X509) *certs;
18 EVP_PKEY *private_key;
19 CRYPTO_refcount_t references;
22 // Passwords are marsahled directly in pinvokes from a SafePasswordHandle that uses different encoding
23 // depending on used PAL (SafePasswordHande.Unix.cs, SafePasswordHande.Windows.cs).
24 // On Unix:es, passwords are stored using Marshal.StringToHGlobalAnsi that can be passed directly to OpenSSL
25 // but on Windows passwords are stored using Marshal.StringToHGlobalUni, most likely because Windows Crypto API
26 // uses Unicode strings for passwords. Instead of changing this pattern (passing passwords as SafePasswordHandle
27 // throught pinvokes) at this particular call site convert things to UTF-8 before calling into OpenSSL.
28 #ifdef WIN32
29 static void
30 deallocate_btls_password (char *password)
32 if (password) {
33 memset (password, 0, strlen (password));
34 free (password);
38 static char *
39 allocate_btls_password (const void *password)
41 char *buffer = NULL;
42 int buffer_size = WideCharToMultiByte (CP_UTF8, 0, (PCWCH)password, -1, NULL, 0, NULL, NULL);
43 if (buffer_size != 0) {
44 buffer = malloc (buffer_size);
45 if (buffer) {
46 buffer [buffer_size - 1] = '\0';
47 if (WideCharToMultiByte (CP_UTF8, 0, (PCWCH)password, -1, buffer, buffer_size, NULL, NULL) == 0) {
48 // Failed to convert buffer.
49 deallocate_btls_password (buffer);
50 buffer = NULL;
55 return buffer;
57 #else
58 static inline void
59 deallocate_btls_password (char *password)
61 return;
64 static inline char *
65 allocate_btls_password (const void *password)
67 return (char *)password;
69 #endif
71 MonoBtlsPkcs12 *
72 mono_btls_pkcs12_new (void)
74 MonoBtlsPkcs12 *pkcs12 = (MonoBtlsPkcs12 *)OPENSSL_malloc (sizeof (MonoBtlsPkcs12));
75 if (pkcs12 == NULL)
76 return NULL;
78 memset (pkcs12, 0, sizeof(MonoBtlsPkcs12));
79 pkcs12->certs = sk_X509_new_null ();
80 pkcs12->references = 1;
81 return pkcs12;
84 int
85 mono_btls_pkcs12_get_count (MonoBtlsPkcs12 *pkcs12)
87 return (int)sk_X509_num (pkcs12->certs);
90 X509 *
91 mono_btls_pkcs12_get_cert (MonoBtlsPkcs12 *pkcs12, int index)
93 X509 *cert;
95 if ((size_t)index >= sk_X509_num (pkcs12->certs))
96 return NULL;
97 cert = sk_X509_value (pkcs12->certs, index);
98 if (cert)
99 X509_up_ref (cert);
100 return cert;
103 STACK_OF(X509) *
104 mono_btls_pkcs12_get_certs (MonoBtlsPkcs12 *pkcs12)
106 return pkcs12->certs;
110 mono_btls_pkcs12_free (MonoBtlsPkcs12 *pkcs12)
112 if (!CRYPTO_refcount_dec_and_test_zero (&pkcs12->references))
113 return 0;
115 sk_X509_pop_free (pkcs12->certs, X509_free);
116 OPENSSL_free (pkcs12);
117 return 1;
120 MonoBtlsPkcs12 *
121 mono_btls_pkcs12_up_ref (MonoBtlsPkcs12 *pkcs12)
123 CRYPTO_refcount_inc (&pkcs12->references);
124 return pkcs12;
127 void
128 mono_btls_pkcs12_add_cert (MonoBtlsPkcs12 *pkcs12, X509 *x509)
130 X509_up_ref (x509);
131 sk_X509_push (pkcs12->certs, x509);
134 static int
135 btls_pkcs12_import (MonoBtlsPkcs12 *pkcs12, const void *data, int len, const char *btls_password)
137 CBS cbs;
138 CBS_init (&cbs, data, len);
139 int ret;
141 ret = PKCS12_get_key_and_certs (&pkcs12->private_key, pkcs12->certs, &cbs, btls_password);
142 if ((ret == 1) || (btls_password && strlen (btls_password) > 0))
143 return ret;
145 // When passed an empty password, we try both NULL and the empty string.
146 CBS_init (&cbs, data, len);
147 if (btls_password)
148 return PKCS12_get_key_and_certs (&pkcs12->private_key, pkcs12->certs, &cbs, NULL);
149 else
150 return PKCS12_get_key_and_certs (&pkcs12->private_key, pkcs12->certs, &cbs, "");
154 mono_btls_pkcs12_import (MonoBtlsPkcs12 *pkcs12, const void *data, int len, const void *password)
156 char *btls_password = allocate_btls_password (password);
157 int ret = btls_pkcs12_import (pkcs12, data, len, btls_password);
158 deallocate_btls_password (btls_password);
159 return ret;
163 mono_btls_pkcs12_has_private_key (MonoBtlsPkcs12 *pkcs12)
165 return pkcs12->private_key != NULL;
168 EVP_PKEY *
169 mono_btls_pkcs12_get_private_key (MonoBtlsPkcs12 *pkcs12)
171 if (!pkcs12->private_key)
172 return NULL;
173 return EVP_PKEY_up_ref (pkcs12->private_key);