summaryrefslogtreecommitdiff
path: root/src/ssl_env.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssl_env.c')
-rw-r--r--src/ssl_env.c435
1 files changed, 435 insertions, 0 deletions
diff --git a/src/ssl_env.c b/src/ssl_env.c
new file mode 100644
index 0000000..4ddff35
--- /dev/null
+++ b/src/ssl_env.c
@@ -0,0 +1,435 @@
+#include <unistd.h>
+#include <string.h>
+#include "fmt.h"
+#include "pathexec.h"
+#include "ucspissl.h"
+#include "stralloc.h"
+#include "str.h"
+
+static char strnum[FMT_ULONG];
+static stralloc ctemp = {0};
+static stralloc *envsa = 0;
+static stralloc btemp = {0};
+static stralloc etemp = {0};
+
+#define set_env_id(n,e,v) \
+if (!set_env_name_entry((n),(e),(v))) return 0
+
+static int env_val(const char *env,const void *val,int len) {
+ const char *v = val;
+ if (envsa) {
+ if (!stralloc_cats(envsa,env)) return 0;
+ if (!stralloc_catb(envsa,"=",1)) return 0;
+ if (!stralloc_catb(envsa,v,len)) return 0;
+ if (!stralloc_0(envsa)) return 0;
+ return 1;
+ }
+ if (!stralloc_copyb(&etemp,v,len)) return 0;
+ if (!stralloc_0(&etemp)) return 0;
+ return pathexec_env(env,etemp.s);
+}
+
+static int env_str(const char *env,const char *val) {
+ if (envsa) {
+ return env_val(env,val,str_len(val));
+ if (!stralloc_cats(envsa,env)) return 0;
+ if (!stralloc_catb(envsa,"=",1)) return 0;
+ if (!stralloc_catb(envsa,val,str_len(val) + 1)) return 0;
+ return 1;
+ }
+ return pathexec_env(env,val);
+}
+
+static int set_env_name_entry(X509_NAME *xname,const char *env,int nid) {
+ X509_NAME_ENTRY *xne;
+ int m;
+ int n;
+
+ if (!env) return 1;
+#if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L))
+ for (m = 0; m < sk_X509_NAME_ENTRY_num(xname->entries); m++) {
+ xne = sk_X509_NAME_ENTRY_value(xname->entries,m);
+ n = OBJ_obj2nid(xne->object);
+ if (n == nid)
+ if (!env_val(env,xne->value->data,xne->value->length)) return 0;
+#else
+ for (m = 0; m < X509_NAME_entry_count(xname); m++) {
+ xne = X509_NAME_get_entry(xname,m);
+ n = OBJ_obj2nid(X509_NAME_ENTRY_get_object(xne));
+ if (n == nid)
+ if (!env_val(env,X509_NAME_ENTRY_get_data(xne)->data,X509_NAME_ENTRY_get_data(xne)->length)) return 0;
+#endif
+ }
+
+ return 1;
+}
+
+int ssl_session_vars(SSL *ssl) {
+ unsigned const char *x;
+ SSL_SESSION *session;
+ unsigned int n = 0;
+ int m;
+ const SSL_CIPHER *cipher;
+ unsigned char u;
+ unsigned char c;
+
+ if (!env_str("SSL_PROTOCOL",SSL_get_version(ssl)))
+ return 0;
+
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) // 0xmnnffppsL
+ session = SSL_get_session(ssl);
+ x = session->session_id;
+ n = session->session_id_length;
+#else
+ session = SSL_get1_session(ssl);
+ x = SSL_SESSION_get_id(session,&n);
+#endif
+
+ if (!stralloc_ready(&btemp,2 * n)) return 0;
+ btemp.len = 2 * n;
+ while (n--) {
+ u = x[n];
+ c = '0' + (u & 15);
+ if (c > '0' + 9) c += 'a' - '0' - 10;
+ btemp.s[2 * n + 1] = c;
+ u >>= 4;
+ c = '0' + (u & 15);
+ if (c > '0' + 9) c += 'a' - '0' - 10;
+ btemp.s[2 * n] = c;
+ }
+ if (!env_val("SSL_SESSION_ID",btemp.s,btemp.len)) return 0;
+
+ if (!env_str("SSL_CIPHER",SSL_get_cipher_name(ssl))) return 0;
+
+ cipher = SSL_get_current_cipher(ssl);
+ if (!cipher) return 0;
+ n = SSL_CIPHER_get_bits(cipher,&m);
+ if (!env_str("SSL_CIPHER_EXPORT",n < 56 ? "true" : "false")) return 0;
+ if (!env_val("SSL_CIPHER_USEKEYSIZE",strnum,fmt_ulong(strnum,n))) return 0;
+ if (!env_val("SSL_CIPHER_ALGKEYSIZE",strnum,fmt_ulong(strnum,m))) return 0;
+
+ if (!env_str("SSL_VERSION_INTERFACE","ucspi-ssl")) return 0;
+ if (!env_str("SSL_VERSION_LIBRARY",OPENSSL_VERSION_TEXT)) return 0;
+
+ return 1;
+}
+
+static int ssl_client_bio_vars(X509 *cert,STACK_OF(X509) *chain,BIO *bio) {
+ ASN1_STRING *astring;
+ int n;
+ int m;
+
+ astring = X509_get_notBefore(cert);
+ if (!ASN1_UTCTIME_print(bio,astring)) return 0;
+ n = BIO_pending(bio);
+ if (!stralloc_ready(&btemp,n)) return 0;
+ btemp.len = n;
+ n = BIO_read(bio,btemp.s,n);
+ if (n != btemp.len) return 0;
+ if (!env_val("SSL_CLIENT_V_START",btemp.s,btemp.len)) return 0;
+
+ astring = X509_get_notAfter(cert);
+ if (!ASN1_UTCTIME_print(bio,astring)) return 0;
+ n = BIO_pending(bio);
+ if (!stralloc_ready(&btemp,n)) return 0;
+ btemp.len = n;
+ n = BIO_read(bio,btemp.s,n);
+ if (n != btemp.len) return 0;
+ if (!env_val("SSL_CLIENT_V_END",btemp.s,btemp.len)) return 0;
+
+ if (!PEM_write_bio_X509(bio,cert)) return 0;
+ n = BIO_pending(bio);
+ if (!stralloc_ready(&btemp,n)) return 0;
+ btemp.len = n;
+ n = BIO_read(bio,btemp.s,n);
+ if (n != btemp.len) return 0;
+ if (!env_val("SSL_CLIENT_CERT",btemp.s,btemp.len)) return 0;
+
+ if (chain) {
+ for (m = 0; m < sk_X509_num(chain); m++) {
+ if (!stralloc_copys(&ctemp,"SSL_CLIENT_CERT_CHAIN_")) return 0;
+ if (!stralloc_catb(&ctemp,strnum,fmt_ulong(strnum,m))) return 0;
+ if (!stralloc_0(&ctemp)) return 0;
+
+ if (m < sk_X509_num(chain)) {
+ if (!PEM_write_bio_X509(bio,sk_X509_value(chain,m))) return 0;
+ n = BIO_pending(bio);
+ if (!stralloc_ready(&btemp,n)) return 0;
+ btemp.len = n;
+ n = BIO_read(bio,btemp.s,n);
+ if (n != btemp.len) return 0;
+ if (!env_val(ctemp.s,btemp.s,btemp.len)) return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int ssl_client_vars(X509 *cert,STACK_OF(X509) *chain) {
+ X509_NAME *xname;
+ X509_PUBKEY *pubkey;
+ const X509_ALGOR *sigalg;
+ const ASN1_OBJECT *calgoid;
+ ASN1_OBJECT *algoid;
+ BIGNUM *bn;
+ BIO *bio;
+ char *x = 0;
+ int n;
+
+ if (!cert) return 1;
+
+ if (!env_val("SSL_CLIENT_M_VERSION",strnum,fmt_ulong(strnum,X509_get_version(cert) + 1)))
+ return 0;
+
+ bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), 0);
+ x = BN_bn2dec(bn);
+ BN_free(bn);
+ if (!env_val("SSL_CLIENT_M_SERIAL",x,strlen(x)))
+ return 0;
+ OPENSSL_free(x);
+
+ xname = X509_get_subject_name(cert);
+ x = X509_NAME_oneline(xname,0,0);
+ n = env_str("SSL_CLIENT_S_DN",x);
+ free(x);
+ if (!n) return 0;
+
+ set_env_id(xname,"SSL_CLIENT_S_DN_C",NID_countryName);
+ set_env_id(xname,"SSL_CLIENT_S_DN_ST",NID_stateOrProvinceName);
+ set_env_id(xname,"SSL_CLIENT_S_DN_L",NID_localityName);
+ set_env_id(xname,"SSL_CLIENT_S_DN_O",NID_organizationName);
+ set_env_id(xname,"SSL_CLIENT_S_DN_OU",NID_organizationalUnitName);
+ set_env_id(xname,"SSL_CLIENT_S_DN_CN",NID_commonName);
+ set_env_id(xname,"SSL_CLIENT_S_DN_T",NID_title);
+ set_env_id(xname,"SSL_CLIENT_S_DN_I",NID_initials);
+ set_env_id(xname,"SSL_CLIENT_S_DN_G",NID_givenName);
+ set_env_id(xname,"SSL_CLIENT_S_DN_S",NID_surname);
+ set_env_id(xname,"SSL_CLIENT_S_DN_D",NID_description);
+ set_env_id(xname,"SSL_CLIENT_S_DN_UID",NID_x500UniqueIdentifier);
+ set_env_id(xname,"SSL_CLIENT_S_DN_Email",NID_pkcs9_emailAddress);
+
+ xname = X509_get_issuer_name(cert);
+ x = X509_NAME_oneline(xname,0,0);
+ n = env_str("SSL_CLIENT_I_DN",x);
+ free(x);
+ if (!n) return 0;
+
+ set_env_id(xname,"SSL_CLIENT_I_DN_C",NID_countryName);
+ set_env_id(xname,"SSL_CLIENT_I_DN_ST",NID_stateOrProvinceName);
+ set_env_id(xname,"SSL_CLIENT_I_DN_L",NID_localityName);
+ set_env_id(xname,"SSL_CLIENT_I_DN_O",NID_organizationName);
+ set_env_id(xname,"SSL_CLIENT_I_DN_OU",NID_organizationalUnitName);
+ set_env_id(xname,"SSL_CLIENT_I_DN_CN",NID_commonName);
+ set_env_id(xname,"SSL_CLIENT_I_DN_T",NID_title);
+ set_env_id(xname,"SSL_CLIENT_I_DN_I",NID_initials);
+ set_env_id(xname,"SSL_CLIENT_I_DN_G",NID_givenName);
+ set_env_id(xname,"SSL_CLIENT_I_DN_S",NID_surname);
+ set_env_id(xname,"SSL_CLIENT_I_DN_D",NID_description);
+ set_env_id(xname,"SSL_CLIENT_I_DN_UID",NID_x500UniqueIdentifier);
+ set_env_id(xname,"SSL_CLIENT_I_DN_Email",NID_pkcs9_emailAddress);
+
+/* Signature Algorithm for PubKey */
+#if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L))
+ n = OBJ_obj2nid(cert->cert_info->signature->algorithm);
+#else
+ sigalg = X509_get0_tbs_sigalg(cert);
+ X509_ALGOR_get0(&calgoid,0,0,sigalg);
+ n = OBJ_obj2nid(calgoid);
+#endif
+ if (!env_str("SSL_CLIENT_A_SIG",(n == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(n)))
+ return 0;
+
+/* Algorithm for PubKey */
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) // 0xmnnffppsL
+ n = OBJ_obj2nid(cert->cert_info->key->algor->algorithm);
+#else
+ pubkey = X509_get_X509_PUBKEY(cert);
+ X509_PUBKEY_get0_param(&algoid,0,0,0,pubkey);
+ n = OBJ_obj2nid(algoid);
+#endif
+ if (!env_str("SSL_CLIENT_A_KEY",(n == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(n)))
+ return 0;
+
+ bio = BIO_new(BIO_s_mem());
+ if (!bio) return 0;
+ n = ssl_client_bio_vars(cert,chain,bio);
+ BIO_free(bio);
+ if (!n) return 0;
+
+ return 1;
+}
+
+static int ssl_server_bio_vars(X509 *cert,STACK_OF(X509) *chain,BIO *bio) {
+ ASN1_STRING *astring;
+ int n;
+ int m;
+
+ astring = X509_get_notBefore(cert);
+ if (!ASN1_UTCTIME_print(bio,astring)) return 0;
+ n = BIO_pending(bio);
+ if (!stralloc_ready(&btemp,n)) return 0;
+ btemp.len = n;
+ n = BIO_read(bio,btemp.s,n);
+ if (n != btemp.len) return 0;
+ if (!env_val("SSL_SERVER_V_START",btemp.s,btemp.len)) return 0;
+
+ astring = X509_get_notAfter(cert);
+ if (!ASN1_UTCTIME_print(bio,astring)) return 0;
+ n = BIO_pending(bio);
+ if (!stralloc_ready(&btemp,n)) return 0;
+ btemp.len = n;
+ n = BIO_read(bio,btemp.s,n);
+ if (n != btemp.len) return 0;
+ if (!env_val("SSL_SERVER_V_END",btemp.s,btemp.len)) return 0;
+
+ if (!PEM_write_bio_X509(bio,cert)) return 0;
+ n = BIO_pending(bio);
+ if (!stralloc_ready(&btemp,n)) return 0;
+ btemp.len = n;
+ n = BIO_read(bio,btemp.s,n);
+ if (n != btemp.len) return 0;
+ if (!env_val("SSL_SERVER_CERT",btemp.s,btemp.len)) return 0;
+
+ if (chain) {
+ for (m = 0; m < sk_X509_num(chain); m++) {
+ if (!stralloc_copys(&ctemp,"SSL_SERVER_CERT_CHAIN_")) return 0;
+ if (!stralloc_catb(&ctemp,strnum,fmt_ulong(strnum,m))) return 0;
+ if (!stralloc_0(&ctemp)) return 0;
+
+ if (m < sk_X509_num(chain)) {
+ if (!PEM_write_bio_X509(bio,sk_X509_value(chain,m))) return 0;
+ n = BIO_pending(bio);
+ if (!stralloc_ready(&btemp,n)) return 0;
+ btemp.len = n;
+ n = BIO_read(bio,btemp.s,n);
+ if (n != btemp.len) return 0;
+ if (!env_val(ctemp.s,btemp.s,btemp.len)) return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int ssl_server_vars(X509 *cert,STACK_OF(X509) *chain) {
+ X509_NAME *xname;
+ X509_PUBKEY *pubkey;
+ const X509_ALGOR *sigalg;
+ const ASN1_OBJECT *calgoid;
+ ASN1_OBJECT *algoid;
+ BIGNUM *bn;
+ BIO *bio;
+ char *x = 0;
+ int n;
+
+ if (!cert) return 1;
+
+ if (!env_val("SSL_SERVER_M_VERSION",strnum,fmt_ulong(strnum,X509_get_version(cert) + 1)))
+ return 0;
+
+ bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), 0);
+ x = BN_bn2dec(bn);
+ BN_free(bn);
+ if (!env_val("SSL_SERVER_M_SERIAL",x,strlen(x))) return 0;
+ OPENSSL_free(x);
+
+ xname = X509_get_subject_name(cert);
+ x = X509_NAME_oneline(xname,0,0);
+ n = env_str("SSL_SERVER_S_DN",x);
+ free(x);
+ if (!n) return 0;
+
+ set_env_id(xname,"SSL_SERVER_S_DN_C",NID_countryName);
+ set_env_id(xname,"SSL_SERVER_S_DN_ST",NID_stateOrProvinceName);
+ set_env_id(xname,"SSL_SERVER_S_DN_L",NID_localityName);
+ set_env_id(xname,"SSL_SERVER_S_DN_O",NID_organizationName);
+ set_env_id(xname,"SSL_SERVER_S_DN_OU",NID_organizationalUnitName);
+ set_env_id(xname,"SSL_SERVER_S_DN_CN",NID_commonName);
+ set_env_id(xname,"SSL_SERVER_S_DN_T",NID_title);
+ set_env_id(xname,"SSL_SERVER_S_DN_I",NID_initials);
+ set_env_id(xname,"SSL_SERVER_S_DN_G",NID_givenName);
+ set_env_id(xname,"SSL_SERVER_S_DN_S",NID_surname);
+ set_env_id(xname,"SSL_SERVER_S_DN_D",NID_description);
+ set_env_id(xname,"SSL_SERVER_S_DN_UID",NID_x500UniqueIdentifier);
+ set_env_id(xname,"SSL_SERVER_S_DN_Email",NID_pkcs9_emailAddress);
+
+ xname = X509_get_issuer_name(cert);
+ x = X509_NAME_oneline(xname,0,0);
+ n = env_str("SSL_SERVER_I_DN",x);
+ free(x);
+ if (!n) return 0;
+
+ set_env_id(xname,"SSL_SERVER_I_DN_C",NID_countryName);
+ set_env_id(xname,"SSL_SERVER_I_DN_ST",NID_stateOrProvinceName);
+ set_env_id(xname,"SSL_SERVER_I_DN_L",NID_localityName);
+ set_env_id(xname,"SSL_SERVER_I_DN_O",NID_organizationName);
+ set_env_id(xname,"SSL_SERVER_I_DN_OU",NID_organizationalUnitName);
+ set_env_id(xname,"SSL_SERVER_I_DN_CN",NID_commonName);
+ set_env_id(xname,"SSL_SERVER_I_DN_T",NID_title);
+ set_env_id(xname,"SSL_SERVER_I_DN_I",NID_initials);
+ set_env_id(xname,"SSL_SERVER_I_DN_G",NID_givenName);
+ set_env_id(xname,"SSL_SERVER_I_DN_S",NID_surname);
+ set_env_id(xname,"SSL_SERVER_I_DN_D",NID_description);
+ set_env_id(xname,"SSL_SERVER_I_DN_UID",NID_x500UniqueIdentifier);
+ set_env_id(xname,"SSL_SERVER_I_DN_Email",NID_pkcs9_emailAddress);
+
+/* Signature Algorithm of PubKey */
+#if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L))
+ n = OBJ_obj2nid(cert->cert_info->signature->algorithm);
+#else
+ sigalg = X509_get0_tbs_sigalg(cert);
+ X509_ALGOR_get0(&calgoid,0,0,sigalg);
+ n = OBJ_obj2nid(calgoid);
+#endif
+ if (!env_str("SSL_SERVER_A_SIG",(n == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(n)))
+ return 0;
+
+/* Algorithm of PubKey */
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) // 0xmnnffppsL
+ n = OBJ_obj2nid(cert->cert_info->key->algor->algorithm);
+#else
+ pubkey = X509_get_X509_PUBKEY(cert);
+ X509_PUBKEY_get0_param(&algoid,0,0,0,pubkey);
+ n = OBJ_obj2nid(algoid);
+#endif
+ if (!env_str("SSL_SERVER_A_KEY",(n == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(n)))
+ return 0;
+
+ bio = BIO_new(BIO_s_mem());
+ if (!bio) return 0;
+ n = ssl_server_bio_vars(cert,chain,bio);
+ BIO_free(bio);
+
+ if (!n) return 0;
+
+ return 1;
+}
+
+int ssl_client_env(SSL *ssl,stralloc *sa) {
+ envsa = sa;
+ if (!ssl_session_vars(ssl)) return 0;
+ if (!ssl_client_vars(SSL_get_certificate(ssl),0))
+ return 0;
+#if (OPENSSL_VERSION_NUMBER > 0x30000000L) // 0xmnnffppsL
+ if (!ssl_server_vars(0,SSL_get_peer_cert_chain(ssl)))
+#else
+ if (!ssl_server_vars(SSL_get_peer_certificate(ssl),SSL_get_peer_cert_chain(ssl)))
+#endif
+ return 0;
+ return 1;
+}
+
+int ssl_server_env(SSL *ssl,stralloc *sa) {
+ envsa = sa;
+ if (!ssl_session_vars(ssl)) return 0;
+ if (!ssl_server_vars(SSL_get_certificate(ssl),0))
+ return 0;
+#if (OPENSSL_VERSION_NUMBER > 0x30000000L) // 0xmnnffppsL
+ if (!ssl_server_vars(0,SSL_get_peer_cert_chain(ssl)))
+#else
+ if (!ssl_client_vars(SSL_get_peer_certificate(ssl),SSL_get_peer_cert_chain(ssl)))
+#endif
+ return 0;
+ return 1;
+}