]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/eap-tls.c
pppd: Fix SIGSEGV in EAP-TLS code when TLS verify method is not specified
[ppp.git] / pppd / eap-tls.c
index 3d8fdc787420b5d5452fe2c413cc80d6fe26e3be..5ac0efb473eedbe1c7bbecc5ee8d1c0d1a77362a 100644 (file)
@@ -64,7 +64,7 @@ static ENGINE *pkey_engine = NULL;
 /* TLSv1.3 do we have a session ticket ? */
 static int have_session_ticket = 0;
 
-int ssl_verify_callback(int, X509_STORE_CTX *); 
+int ssl_verify_callback(int, X509_STORE_CTX *);
 void ssl_msg_callback(int write_p, int version, int ct, const void *buf,
               size_t len, SSL * ssl, void *arg);
 int ssl_new_session_cb(SSL *s, SSL_SESSION *sess);
@@ -508,7 +508,6 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
     {
         EVP_PKEY   *pkey = NULL;
         PW_CB_DATA  cb_data;
-        UI_METHOD* transfer_pin = NULL;
 
         cb_data.password = passwd;
         cb_data.prompt_info = pkey_identifier;
@@ -534,6 +533,8 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
 
             dbglog( "Using our private key '%s' in engine", pkey_identifier );
             pkey = ENGINE_load_private_key(pkey_engine, pkey_identifier, transfer_pin, &cb_data);
+
+            if (transfer_pin) UI_destroy_method(transfer_pin);
         }
         else {
             dbglog( "Loading private key '%s' from engine", pkey_identifier );
@@ -553,8 +554,6 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
             warn("EAP-TLS: Cannot load PKCS11 key %s", pkey_identifier);
             log_ssl_errors();
         }
-
-        if (transfer_pin) UI_destroy_method(transfer_pin);
     }
     else
     {
@@ -734,6 +733,7 @@ int eaptls_init_ssl_server(eap_state * esp)
     if (!esp->es_server.ea_session)
         fatal("Allocation error");
     ets = esp->es_server.ea_session;
+    ets->client = 0;
 
     if (!esp->es_server.ea_peer) {
         error("EAP-TLS: Error: client name not set (BUG)");
@@ -825,6 +825,7 @@ int eaptls_init_ssl_client(eap_state * esp)
     if (!esp->es_client.ea_session)
         fatal("Allocation error");
     ets = esp->es_client.ea_session;
+    ets->client = 1;
 
     /*
      * If available, copy server name in ets; it will be used in cert
@@ -982,7 +983,7 @@ int eaptls_receive(struct eaptls_session *ets, u_char * inp, int len)
  
         ets->data = malloc(len);
         if (!ets->data)
-            fatal("EAP-TLS: allocation error\n");
+            fatal("EAP-TLS: memory allocation error in eaptls_receive\n");
  
         ets->datalen = 0;
         ets->tlslen = len;
@@ -1065,11 +1066,13 @@ int eaptls_send(struct eaptls_session *ets, u_char ** outp)
         ets->datalen = res;
 
         ets->data = malloc(ets->datalen);
+        if (!ets->data)
+            fatal("EAP-TLS: memory allocation error in eaptls_send\n");
+
         BCOPY(fromtls, ets->data, ets->datalen);
 
         ets->offset = 0;
         first = 1;
-
     }
 
     size = ets->datalen - ets->offset;
@@ -1145,6 +1148,7 @@ int ssl_verify_callback(int ok, X509_STORE_CTX * ctx)
     int err, depth;
     SSL *ssl;
     struct eaptls_session *ets;
+    char *ptr1 = NULL, *ptr2 = NULL;
 
     peer_cert = X509_STORE_CTX_get_current_cert(ctx);
     err = X509_STORE_CTX_get_error(ctx);
@@ -1180,34 +1184,71 @@ int ssl_verify_callback(int ok, X509_STORE_CTX * ctx)
 
     if (!depth) 
     {
-        /* This is the peer certificate */
-
-        X509_NAME_oneline(X509_get_subject_name(peer_cert),
-                  subject, 256);
+        /* Verify certificate based on certificate type and extended key usage */
+        if (tls_verify_key_usage) {
+            int purpose = ets->client ? X509_PURPOSE_SSL_SERVER : X509_PURPOSE_SSL_CLIENT ;
+            if (X509_check_purpose(peer_cert, purpose, 0) == 0) {
+                error("Certificate verification error: nsCertType mismatch");
+                return 0;
+            }
 
-        X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert),
-                      NID_commonName, cn_str, 256);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+            int flags = ets->client ? XKU_SSL_SERVER : XKU_SSL_CLIENT;
+            if (!(X509_get_extended_key_usage(peer_cert) & flags)) {
+                error("Certificate verification error: invalid extended key usage");
+                return 0;
+            }
+#endif
+            info("Certificate key usage: OK");
+        }
 
         /*
          * If acting as client and the name of the server wasn't specified
          * explicitely, we can't verify the server authenticity 
          */
-        if (!ets->peer[0]) {
-            warn("Peer name not specified: no check");
+        if (!tls_verify_method)
+            tls_verify_method = TLS_VERIFY_NONE;
+
+        if (!ets->peer[0] || !strcmp(TLS_VERIFY_NONE, tls_verify_method)) {
+            warn("Certificate verication disabled or no peer name was specified");
             return ok;
         }
 
-        /*
-         * Check the CN 
-         */
-        if (strcmp(cn_str, ets->peer)) {
-            error
-                ("Certificate verification error: CN (%s) != peer_name (%s)",
-                 cn_str, ets->peer);
+        /* This is the peer certificate */
+        X509_NAME_oneline(X509_get_subject_name(peer_cert),
+                  subject, 256);
+
+        X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert),
+                      NID_commonName, cn_str, 256);
+
+        /* Verify based on subject name */
+        ptr1 = ets->peer;
+        if (!strcmp(TLS_VERIFY_SUBJECT, tls_verify_method)) {
+            ptr2 = subject;
+        }
+
+        /* Verify based on common name (default) */
+        if (strlen(tls_verify_method) == 0 ||
+            !strcmp(TLS_VERIFY_NAME, tls_verify_method)) {
+            ptr2 = cn_str;
+        }
+
+        /* Match the suffix of common name */
+        if (!strcmp(TLS_VERIFY_SUFFIX, tls_verify_method)) {
+            int len = strlen(ptr1);
+            int off = strlen(cn_str) - len;
+            ptr2 = cn_str;
+            if (off > 0) {
+                ptr2 = cn_str + off;
+            }
+        }
+
+        if (strcmp(ptr1, ptr2)) {
+            error("Certificate verification error: CN (%s) != %s", ptr1, ptr2);
             return 0;
         }
 
-        warn("Certificate CN: %s , peer name %s", cn_str, ets->peer);
+        info("Certificate CN: %s, peer name %s", cn_str, ets->peer);
 
         /*
          * If a peer certificate file was specified, here we check it