]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/tls2.c
ITS#8753 Public key pinning support in libldap
[openldap] / libraries / libldap / tls2.c
index 04db61234c3bed31f0899d3c19323090622292ee..1feba5befd56ceef025d91c15d2fc0c6313f1ec0 100644 (file)
@@ -138,6 +138,14 @@ ldap_int_tls_destroy( struct ldapoptions *lo )
                LDAP_FREE( lo->ldo_tls_crlfile );
                lo->ldo_tls_crlfile = NULL;
        }
+       /* tls_pin_hashalg and tls_pin share the same buffer */
+       if ( lo->ldo_tls_pin_hashalg ) {
+               LDAP_FREE( lo->ldo_tls_pin_hashalg );
+               lo->ldo_tls_pin_hashalg = NULL;
+       } else {
+               LDAP_FREE( lo->ldo_tls_pin.bv_val );
+       }
+       BER_BVZERO( &lo->ldo_tls_pin );
 }
 
 /*
@@ -518,6 +526,18 @@ ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in )
                }
        }
 
+       /*
+        * If instructed to do pinning, do it now
+        */
+       if ( !BER_BVISNULL( &ld->ld_options.ldo_tls_pin ) ) {
+               ld->ld_errno = tls_imp->ti_session_pinning( ld, s,
+                               ld->ld_options.ldo_tls_pin_hashalg,
+                               &ld->ld_options.ldo_tls_pin );
+               if (ld->ld_errno != LDAP_SUCCESS) {
+                       return ld->ld_errno;
+               }
+       }
+
        return LDAP_SUCCESS;
 }
 
@@ -534,6 +554,7 @@ ldap_pvt_tls_config( LDAP *ld, int option, const char *arg )
        case LDAP_OPT_X_TLS_RANDOM_FILE:
        case LDAP_OPT_X_TLS_CIPHER_SUITE:
        case LDAP_OPT_X_TLS_DHFILE:
+       case LDAP_OPT_X_TLS_PEERKEY_HASH:
        case LDAP_OPT_X_TLS_CRLFILE:    /* GnuTLS only */
                return ldap_pvt_tls_set_option( ld, option, (void *) arg );
 
@@ -946,6 +967,68 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg )
                        BER_BVZERO( &lo->ldo_tls_key );
                }
                break;
+       case LDAP_OPT_X_TLS_PEERKEY_HASH: {
+               /* arg = "[hashalg:]pubkey_hash" */
+               struct berval bv;
+               char *p, *pin = arg;
+               int rc = LDAP_SUCCESS;
+
+               if ( !tls_imp->ti_session_pinning ) return -1;
+
+               if ( !pin ) {
+                       if ( lo->ldo_tls_pin_hashalg ) {
+                               LDAP_FREE( lo->ldo_tls_pin_hashalg );
+                       } else if ( lo->ldo_tls_pin.bv_val ) {
+                               LDAP_FREE( lo->ldo_tls_pin.bv_val );
+                       }
+                       lo->ldo_tls_pin_hashalg = NULL;
+                       BER_BVZERO( &lo->ldo_tls_pin );
+                       return rc;
+               }
+
+               pin = LDAP_STRDUP( pin );
+               p = strchr( pin, ':' );
+
+               /* pubkey (its hash) goes in bv, alg in p */
+               if ( p ) {
+                       *p = '\0';
+                       bv.bv_val = p+1;
+                       p = pin;
+               } else {
+                       bv.bv_val = pin;
+               }
+
+               bv.bv_len = strlen(bv.bv_val);
+               if ( ldap_int_decode_b64_inplace( &bv ) ) {
+                       LDAP_FREE( pin );
+                       return -1;
+               }
+
+               if ( ld != NULL ) {
+                       LDAPConn *conn = ld->ld_defconn;
+                       if ( conn != NULL ) {
+                               Sockbuf *sb = conn->lconn_sb;
+                               void *sess = ldap_pvt_tls_sb_ctx( sb );
+                               if ( sess != NULL ) {
+                                       rc = tls_imp->ti_session_pinning( ld, sess, p, &bv );
+                               }
+                       }
+               }
+
+               if ( rc == LDAP_SUCCESS ) {
+                       if ( lo->ldo_tls_pin_hashalg ) {
+                               LDAP_FREE( lo->ldo_tls_pin_hashalg );
+                       } else if ( lo->ldo_tls_pin.bv_val ) {
+                               LDAP_FREE( lo->ldo_tls_pin.bv_val );
+                       }
+                       lo->ldo_tls_pin_hashalg = p;
+                       lo->ldo_tls_pin = bv;
+               } else {
+                       LDAP_FREE( pin );
+               }
+
+               return rc;
+       }
        default:
                return -1;
        }