ucspi-ssl 0.13.03
ucspi-ssl
Loading...
Searching...
No Matches
ssl_env.c
Go to the documentation of this file.
1#include <unistd.h>
2#include <string.h>
3#include "fmt.h"
4#include "pathexec.h"
5#include "ucspissl.h"
6#include "stralloc.h"
7#include "str.h"
8
9static char strnum[FMT_ULONG];
10static stralloc ctemp = {0};
11static stralloc *envsa = 0;
12static stralloc btemp = {0};
13static stralloc etemp = {0};
14
15#define set_env_id(n,e,v) \
16if (!set_env_name_entry((n),(e),(v))) return 0
17
18static int env_val(const char *env,const void *val,int len)
19{
20 const char *v = val;
21 if (envsa) {
22 if (!stralloc_cats(envsa,env)) return 0;
23 if (!stralloc_catb(envsa,"=",1)) return 0;
24 if (!stralloc_catb(envsa,v,len)) return 0;
25 if (!stralloc_0(envsa)) return 0;
26 return 1;
27 }
28 if (!stralloc_copyb(&etemp,v,len)) return 0;
29 if (!stralloc_0(&etemp)) return 0;
30 return pathexec_env(env,etemp.s);
31}
32
33static int env_str(const char *env,const char *val)
34{
35 if (envsa) {
36 return env_val(env,val,str_len(val));
37 if (!stralloc_cats(envsa,env)) return 0;
38 if (!stralloc_catb(envsa,"=",1)) return 0;
39 if (!stralloc_catb(envsa,val,str_len(val) + 1)) return 0;
40 return 1;
41 }
42 return pathexec_env(env,val);
43}
44
45static int set_env_name_entry(X509_NAME *xname,const char *env,int nid)
46{
47 X509_NAME_ENTRY *xne;
48 int m;
49 int n;
50
51 if (!env) return 1;
52 for (m = 0; m < X509_NAME_entry_count(xname); m++) {
53 xne = X509_NAME_get_entry(xname,m);
54 n = OBJ_obj2nid(X509_NAME_ENTRY_get_object(xne));
55 if (n == nid)
56 if (!env_val(env,X509_NAME_ENTRY_get_data(xne)->data,X509_NAME_ENTRY_get_data(xne)->length)) return 0;
57 }
58
59 return 1;
60}
61
62int ssl_session_vars(SSL *ssl)
63{
64 unsigned const char *x;
65 SSL_SESSION *session;
66 unsigned int n = 0;
67 int m;
68 const SSL_CIPHER *cipher;
69 unsigned char u;
70 unsigned char c;
71
72 if (!env_str("SSL_PROTOCOL",SSL_get_version(ssl)))
73 return 0;
74
75 session = SSL_get1_session(ssl);
76 x = SSL_SESSION_get_id(session,&n);
77
78 if (!stralloc_ready(&btemp,2 * n)) return 0;
79 btemp.len = 2 * n;
80 while (n--) {
81 u = x[n];
82 c = '0' + (u & 15);
83 if (c > '0' + 9) c += 'a' - '0' - 10;
84 btemp.s[2 * n + 1] = c;
85 u >>= 4;
86 c = '0' + (u & 15);
87 if (c > '0' + 9) c += 'a' - '0' - 10;
88 btemp.s[2 * n] = c;
89 }
90 if (!env_val("SSL_SESSION_ID",btemp.s,btemp.len)) return 0;
91
92 if (!env_str("SSL_CIPHER",SSL_get_cipher_name(ssl))) return 0;
93
94 cipher = SSL_get_current_cipher(ssl);
95 if (!cipher) return 0;
96 n = SSL_CIPHER_get_bits(cipher,&m);
97 if (!env_str("SSL_CIPHER_EXPORT",n < 56 ? "true" : "false")) return 0;
98 if (!env_val("SSL_CIPHER_USEKEYSIZE",strnum,fmt_ulong(strnum,n))) return 0;
99 if (!env_val("SSL_CIPHER_ALGKEYSIZE",strnum,fmt_ulong(strnum,m))) return 0;
100
101 if (!env_str("SSL_VERSION_INTERFACE","ucspi-ssl")) return 0;
102 if (!env_str("SSL_VERSION_LIBRARY",OPENSSL_VERSION_TEXT)) return 0;
103
104 return 1;
105}
106
107static int ssl_client_bio_vars(X509 *cert,STACK_OF(X509) *chain,BIO *bio)
108{
109 ASN1_STRING *astring;
110 int n;
111 int m;
112
113 astring = X509_get_notBefore(cert);
114 if (!ASN1_UTCTIME_print(bio,astring)) return 0;
115 n = BIO_pending(bio);
116 if (!stralloc_ready(&btemp,n)) return 0;
117 btemp.len = n;
118 n = BIO_read(bio,btemp.s,n);
119 if (n != btemp.len) return 0;
120 if (!env_val("SSL_CLIENT_V_START",btemp.s,btemp.len)) return 0;
121
122 astring = X509_get_notAfter(cert);
123 if (!ASN1_UTCTIME_print(bio,astring)) return 0;
124 n = BIO_pending(bio);
125 if (!stralloc_ready(&btemp,n)) return 0;
126 btemp.len = n;
127 n = BIO_read(bio,btemp.s,n);
128 if (n != btemp.len) return 0;
129 if (!env_val("SSL_CLIENT_V_END",btemp.s,btemp.len)) return 0;
130
131 if (!PEM_write_bio_X509(bio,cert)) return 0;
132 n = BIO_pending(bio);
133 if (!stralloc_ready(&btemp,n)) return 0;
134 btemp.len = n;
135 n = BIO_read(bio,btemp.s,n);
136 if (n != btemp.len) return 0;
137 if (!env_val("SSL_CLIENT_CERT",btemp.s,btemp.len)) return 0;
138
139 if (chain) {
140 for (m = 0; m < sk_X509_num(chain); m++) {
141 if (!stralloc_copys(&ctemp,"SSL_CLIENT_CERT_CHAIN_")) return 0;
142 if (!stralloc_catb(&ctemp,strnum,fmt_ulong(strnum,m))) return 0;
143 if (!stralloc_0(&ctemp)) return 0;
144
145 if (m < sk_X509_num(chain)) {
146 if (!PEM_write_bio_X509(bio,sk_X509_value(chain,m))) return 0;
147 n = BIO_pending(bio);
148 if (!stralloc_ready(&btemp,n)) return 0;
149 btemp.len = n;
150 n = BIO_read(bio,btemp.s,n);
151 if (n != btemp.len) return 0;
152 if (!env_val(ctemp.s,btemp.s,btemp.len)) return 0;
153 }
154 }
155 }
156
157 return 1;
158}
159
160static int ssl_client_vars(X509 *cert,STACK_OF(X509) *chain)
161{
162 X509_NAME *xname;
163 X509_PUBKEY *pubkey;
164 const X509_ALGOR *sigalg;
165 const ASN1_OBJECT *calgoid;
166 ASN1_OBJECT *algoid;
167 BIGNUM *bn;
168 BIO *bio;
169 char *x = 0;
170 int n;
171 char *yname;
172
173 if (!cert) return 1;
174
175 if (!env_val("SSL_CLIENT_M_VERSION",strnum,fmt_ulong(strnum,X509_get_version(cert) + 1)))
176 return 0;
177
178 bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), 0);
179 x = BN_bn2dec(bn);
180 BN_free(bn);
181 if (!env_val("SSL_CLIENT_M_SERIAL",x,strlen(x)))
182 return 0;
183 OPENSSL_free(x);
184
185/* Elements of the Subject DN */
186 xname = X509_get_subject_name(cert);
187 x = X509_NAME_oneline(xname,0,0);
188 n = env_str("SSL_CLIENT_S_DN",x);
189 free(x);
190 if (!n) return 0;
191
192 set_env_id(xname,"SSL_CLIENT_S_DN_C",NID_countryName);
193 set_env_id(xname,"SSL_CLIENT_S_DN_ST",NID_stateOrProvinceName);
194 set_env_id(xname,"SSL_CLIENT_S_DN_L",NID_localityName);
195 set_env_id(xname,"SSL_CLIENT_S_DN_O",NID_organizationName);
196 set_env_id(xname,"SSL_CLIENT_S_DN_OU",NID_organizationalUnitName);
197 set_env_id(xname,"SSL_CLIENT_S_DN_CN",NID_commonName);
198 set_env_id(xname,"SSL_CLIENT_S_DN_T",NID_title);
199 set_env_id(xname,"SSL_CLIENT_S_DN_I",NID_initials);
200 set_env_id(xname,"SSL_CLIENT_S_DN_G",NID_givenName);
201 set_env_id(xname,"SSL_CLIENT_S_DN_S",NID_surname);
202 set_env_id(xname,"SSL_CLIENT_S_DN_D",NID_description);
203 set_env_id(xname,"SSL_CLIENT_S_DN_UID",NID_x500UniqueIdentifier);
204 set_env_id(xname,"SSL_CLIENT_S_DN_Email",NID_pkcs9_emailAddress);
205
206/* Elements of the Issuer DN */
207 xname = X509_get_issuer_name(cert);
208 x = X509_NAME_oneline(xname,0,0);
209 n = env_str("SSL_CLIENT_I_DN",x);
210 free(x);
211 if (!n) return 0;
212
213 set_env_id(xname,"SSL_CLIENT_I_DN_C",NID_countryName);
214 set_env_id(xname,"SSL_CLIENT_I_DN_ST",NID_stateOrProvinceName);
215 set_env_id(xname,"SSL_CLIENT_I_DN_L",NID_localityName);
216 set_env_id(xname,"SSL_CLIENT_I_DN_O",NID_organizationName);
217 set_env_id(xname,"SSL_CLIENT_I_DN_OU",NID_organizationalUnitName);
218 set_env_id(xname,"SSL_CLIENT_I_DN_CN",NID_commonName);
219 set_env_id(xname,"SSL_CLIENT_I_DN_T",NID_title);
220 set_env_id(xname,"SSL_CLIENT_I_DN_I",NID_initials);
221 set_env_id(xname,"SSL_CLIENT_I_DN_G",NID_givenName);
222 set_env_id(xname,"SSL_CLIENT_I_DN_S",NID_surname);
223 set_env_id(xname,"SSL_CLIENT_I_DN_D",NID_description);
224 set_env_id(xname,"SSL_CLIENT_I_DN_UID",NID_x500UniqueIdentifier);
225 set_env_id(xname,"SSL_CLIENT_I_DN_Email",NID_pkcs9_emailAddress);
226
227/* Signature Algorithm for PubKey */
228 sigalg = X509_get0_tbs_sigalg(cert);
229 X509_ALGOR_get0(&calgoid,0,0,sigalg);
230 n = OBJ_obj2nid(calgoid);
231 if (!env_str("SSL_CLIENT_A_SIG",(n == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(n)))
232 return 0;
233
234/* Algorithm for PubKey */
235 pubkey = X509_get_X509_PUBKEY(cert);
236 X509_PUBKEY_get0_param(&algoid,0,0,0,pubkey);
237 n = OBJ_obj2nid(algoid);
238 if (!env_str("SSL_CLIENT_A_KEY",(n == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(n)))
239 return 0;
240
241/* Subject Alternative Name Values (SAN) [what a bad interface] */
242
243 GENERAL_NAMES *extensions = X509_get_ext_d2i(cert,NID_subject_alt_name,0,0);
244 int num = sk_GENERAL_NAME_num(extensions); /* num = 0, if no SAN extensions */
245
246 for (int i = 0, n = 0; i < num; ++i) {
247 const GENERAL_NAME *ext = sk_GENERAL_NAME_value(extensions,i);
248 if (ext->type == GEN_DNS) {
249 if (OBJ_sn2nid((const char*)ext->d.ia5) != V_ASN1_IA5STRING) continue;
250 yname = (char *)ASN1_STRING_get0_data(ext->d.ia5);
251 if (n == 0) {
252 if (!env_str("SSL_CLIENT_SAN_DNS_0=",yname)) return 0;
253 } else n = 1;
254 if (n == 1)
255 if (!env_str("SSL_CLIENT_SAN_DNS_1=",yname)) return 0;
256 }
257 if (ext->type == GEN_EMAIL) {
258 n = 0;
259 if (OBJ_sn2nid((const char*)ext->d.ia5) != V_ASN1_IA5STRING) continue;
260 yname = (char *)ASN1_STRING_get0_data(ext->d.ia5);
261 if (n == 0) {
262 if (!env_str("SSL_CLIENT_SAN_Email_0=",yname)) return 0;
263 } else n = 1;
264 if (n == 1)
265 if (!env_str("SSL_CLIENT_SAN_Email_1=",yname)) return 0;
266 }
267 }
268
269 bio = BIO_new(BIO_s_mem());
270 if (!bio) return 0;
271 n = ssl_client_bio_vars(cert,chain,bio);
272 BIO_free(bio);
273 if (!n) return 0;
274
275 return 1;
276}
277
278static int ssl_server_bio_vars(X509 *cert,STACK_OF(X509) *chain,BIO *bio)
279{
280 ASN1_STRING *astring;
281 int n;
282 int m;
283
284 astring = X509_get_notBefore(cert);
285 if (!ASN1_UTCTIME_print(bio,astring)) return 0;
286 n = BIO_pending(bio);
287 if (!stralloc_ready(&btemp,n)) return 0;
288 btemp.len = n;
289 n = BIO_read(bio,btemp.s,n);
290 if (n != btemp.len) return 0;
291 if (!env_val("SSL_SERVER_V_START",btemp.s,btemp.len)) return 0;
292
293 astring = X509_get_notAfter(cert);
294 if (!ASN1_UTCTIME_print(bio,astring)) return 0;
295 n = BIO_pending(bio);
296 if (!stralloc_ready(&btemp,n)) return 0;
297 btemp.len = n;
298 n = BIO_read(bio,btemp.s,n);
299 if (n != btemp.len) return 0;
300 if (!env_val("SSL_SERVER_V_END",btemp.s,btemp.len)) return 0;
301
302 if (!PEM_write_bio_X509(bio,cert)) return 0;
303 n = BIO_pending(bio);
304 if (!stralloc_ready(&btemp,n)) return 0;
305 btemp.len = n;
306 n = BIO_read(bio,btemp.s,n);
307 if (n != btemp.len) return 0;
308 if (!env_val("SSL_SERVER_CERT",btemp.s,btemp.len)) return 0;
309
310 if (chain) {
311 for (m = 0; m < sk_X509_num(chain); m++) {
312 if (!stralloc_copys(&ctemp,"SSL_SERVER_CERT_CHAIN_")) return 0;
313 if (!stralloc_catb(&ctemp,strnum,fmt_ulong(strnum,m))) return 0;
314 if (!stralloc_0(&ctemp)) return 0;
315
316 if (m < sk_X509_num(chain)) {
317 if (!PEM_write_bio_X509(bio,sk_X509_value(chain,m))) return 0;
318 n = BIO_pending(bio);
319 if (!stralloc_ready(&btemp,n)) return 0;
320 btemp.len = n;
321 n = BIO_read(bio,btemp.s,n);
322 if (n != btemp.len) return 0;
323 if (!env_val(ctemp.s,btemp.s,btemp.len)) return 0;
324 }
325 }
326 }
327
328 return 1;
329}
330
331static int ssl_server_vars(X509 *cert,STACK_OF(X509) *chain)
332{
333 X509_NAME *xname;
334 X509_PUBKEY *pubkey;
335 const X509_ALGOR *sigalg;
336 const ASN1_OBJECT *calgoid;
337 ASN1_OBJECT *algoid;
338 BIGNUM *bn;
339 BIO *bio;
340 char *x = 0;
341 int n;
342 char *yname;
343
344 if (!cert) return 1;
345
346 if (!env_val("SSL_SERVER_M_VERSION",strnum,fmt_ulong(strnum,X509_get_version(cert) + 1)))
347 return 0;
348
349 bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), 0);
350 x = BN_bn2dec(bn);
351 BN_free(bn);
352 if (!env_val("SSL_SERVER_M_SERIAL",x,strlen(x))) return 0;
353 OPENSSL_free(x);
354
355 xname = X509_get_subject_name(cert);
356 x = X509_NAME_oneline(xname,0,0);
357 n = env_str("SSL_SERVER_S_DN",x);
358 free(x);
359 if (!n) return 0;
360
361 set_env_id(xname,"SSL_SERVER_S_DN_C",NID_countryName);
362 set_env_id(xname,"SSL_SERVER_S_DN_ST",NID_stateOrProvinceName);
363 set_env_id(xname,"SSL_SERVER_S_DN_L",NID_localityName);
364 set_env_id(xname,"SSL_SERVER_S_DN_O",NID_organizationName);
365 set_env_id(xname,"SSL_SERVER_S_DN_OU",NID_organizationalUnitName);
366 set_env_id(xname,"SSL_SERVER_S_DN_CN",NID_commonName);
367 set_env_id(xname,"SSL_SERVER_S_DN_T",NID_title);
368 set_env_id(xname,"SSL_SERVER_S_DN_I",NID_initials);
369 set_env_id(xname,"SSL_SERVER_S_DN_G",NID_givenName);
370 set_env_id(xname,"SSL_SERVER_S_DN_S",NID_surname);
371 set_env_id(xname,"SSL_SERVER_S_DN_D",NID_description);
372 set_env_id(xname,"SSL_SERVER_S_DN_UID",NID_x500UniqueIdentifier);
373 set_env_id(xname,"SSL_SERVER_S_DN_Email",NID_pkcs9_emailAddress);
374
375 xname = X509_get_issuer_name(cert);
376 x = X509_NAME_oneline(xname,0,0);
377 n = env_str("SSL_SERVER_I_DN",x);
378 free(x);
379 if (!n) return 0;
380
381 set_env_id(xname,"SSL_SERVER_I_DN_C",NID_countryName);
382 set_env_id(xname,"SSL_SERVER_I_DN_ST",NID_stateOrProvinceName);
383 set_env_id(xname,"SSL_SERVER_I_DN_L",NID_localityName);
384 set_env_id(xname,"SSL_SERVER_I_DN_O",NID_organizationName);
385 set_env_id(xname,"SSL_SERVER_I_DN_OU",NID_organizationalUnitName);
386 set_env_id(xname,"SSL_SERVER_I_DN_CN",NID_commonName);
387 set_env_id(xname,"SSL_SERVER_I_DN_T",NID_title);
388 set_env_id(xname,"SSL_SERVER_I_DN_I",NID_initials);
389 set_env_id(xname,"SSL_SERVER_I_DN_G",NID_givenName);
390 set_env_id(xname,"SSL_SERVER_I_DN_S",NID_surname);
391 set_env_id(xname,"SSL_SERVER_I_DN_D",NID_description);
392 set_env_id(xname,"SSL_SERVER_I_DN_UID",NID_x500UniqueIdentifier);
393 set_env_id(xname,"SSL_SERVER_I_DN_Email",NID_pkcs9_emailAddress);
394
395/* Signature Algorithm of PubKey */
396 sigalg = X509_get0_tbs_sigalg(cert);
397 X509_ALGOR_get0(&calgoid,0,0,sigalg);
398 n = OBJ_obj2nid(calgoid);
399 if (!env_str("SSL_SERVER_A_SIG",(n == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(n)))
400 return 0;
401
402/* Algorithm of PubKey */
403 pubkey = X509_get_X509_PUBKEY(cert);
404 X509_PUBKEY_get0_param(&algoid,0,0,0,pubkey);
405 n = OBJ_obj2nid(algoid);
406 if (!env_str("SSL_SERVER_A_KEY",(n == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(n)))
407 return 0;
408
409/* Subject Alternative Name Values (SAN) [what a bad interface] */
410
411 GENERAL_NAMES *extensions = X509_get_ext_d2i(cert,NID_subject_alt_name,0,0);
412 int num = sk_GENERAL_NAME_num(extensions); /* num = 0, if no SAN extensions */
413
414 for (int i = 0, n = 0; i < num; ++i) {
415 const GENERAL_NAME *ext = sk_GENERAL_NAME_value(extensions,i);
416 if (ext->type == GEN_DNS) {
417 if (OBJ_sn2nid((const char*)ext->d.ia5) != V_ASN1_IA5STRING) continue;
418 yname = (char *)ASN1_STRING_get0_data(ext->d.ia5);
419 if (n == 0) {
420 if (!env_str("SSL_SERVER_SAN_DNS_0=",yname)) return 0;
421 } else n = 1;
422 if (n == 1)
423 if (!env_str("SSL_SERVER_SAN_DNS_1=",yname)) return 0;
424 }
425 if (ext->type == GEN_EMAIL) {
426 n = 0;
427 if (OBJ_sn2nid((const char*)ext->d.ia5) != V_ASN1_IA5STRING) continue;
428 yname = (char *)ASN1_STRING_get0_data(ext->d.ia5);
429 if (n == 0) {
430 if (!env_str("SSL_SERVER_SAN_Email_0=",yname)) return 0;
431 } else n = 1;
432 if (n == 1)
433 if (!env_str("SSL_SERVER_SAN_Email_1=",yname)) return 0;
434 }
435 }
436
437 bio = BIO_new(BIO_s_mem());
438 if (!bio) return 0;
439 n = ssl_server_bio_vars(cert,chain,bio);
440 BIO_free(bio);
441
442 if (!n) return 0;
443
444 return 1;
445}
446
447int ssl_client_env(SSL *ssl,stralloc *sa)
448{
449 envsa = sa;
450 if (!ssl_session_vars(ssl)) return 0;
451 if (!ssl_client_vars(SSL_get_certificate(ssl),0)) return 0;
452 if (!ssl_server_vars(0,SSL_get_peer_cert_chain(ssl))) return 0;
453 return 1;
454}
455
456int ssl_server_env(SSL *ssl,stralloc *sa)
457{
458 envsa = sa;
459 if (!ssl_session_vars(ssl)) return 0;
460 if (!ssl_server_vars(SSL_get_certificate(ssl),0)) return 0;
461 if (!ssl_server_vars(0,SSL_get_peer_cert_chain(ssl))) return 0;
462 return 1;
463}
#define set_env_id(n, e, v)
Definition: ssl_env.c:15
int ssl_server_env(SSL *ssl, stralloc *sa)
Definition: ssl_env.c:456
int ssl_client_env(SSL *ssl, stralloc *sa)
Definition: ssl_env.c:447
int ssl_session_vars(SSL *ssl)
Definition: ssl_env.c:62
void env(const char *s, const char *t)
Definition: sslclient.c:43
X509 * cert
Definition: sslhandle.c:126
Header file to be used with sqmail; previously called ssl.h. (name clash)