]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Fix for #1132
authorBrian Wickman <bwickman97@outlook.com>
Thu, 21 Apr 2022 05:52:36 +0000 (05:52 +0000)
committerDaiki Ueno <ueno@gnu.org>
Thu, 21 Apr 2022 05:52:36 +0000 (05:52 +0000)
.gitignore
lib/includes/gnutls/gnutls.h.in
lib/x509/common.h
lib/x509/name_constraints.c
lib/x509/output.c
lib/x509/virt-san.c
lib/x509/x509.c
tests/Makefile.am
tests/x509-upnconstraint.c [new file with mode: 0644]

index 6d349287e2437f01a387d2412f5f3d694482b7bd..551efc29079d95973796f9f2a19bdd2948739ab1 100644 (file)
@@ -904,6 +904,7 @@ tests/x509-dn-decode
 tests/x509-dn-decode-compat
 tests/x509-extensions
 tests/x509-server-verify
+tests/x509-upnconstraint
 tests/x509-verify-with-crl
 tests/x509_altname
 tests/x509cert
index 55d33cf259efb62032f57d26659eb3e4756d74e4..f8c0faff9628ca43e7885dbf62e585baaed9ef7c 100644 (file)
@@ -2744,6 +2744,7 @@ gnutls_psk_set_server_params_function(gnutls_psk_server_credentials_t
  * @GNUTLS_SAN_REGISTERED_ID: RegisteredID.
  * @GNUTLS_SAN_OTHERNAME_XMPP: Virtual SAN, used by certain functions for convenience.
  * @GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL: Virtual SAN, used by certain functions for convenience.
+ * @GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL: Virtual SAN, used by certain functions for convenience.
  *
  * Enumeration of different subject alternative names types.
  */
@@ -2760,7 +2761,8 @@ typedef enum gnutls_x509_subject_alt_name_t {
           that they are represented by an otherName value and an OID.
           Used by gnutls_x509_crt_get_subject_alt_othername_oid.  */
        GNUTLS_SAN_OTHERNAME_XMPP = 1000,
-       GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL
+       GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL,
+       GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL
 } gnutls_x509_subject_alt_name_t;
 
 struct gnutls_openpgp_crt_int;
index c1df15980f3deb23b2811ef7ec2a658183630fae..19d29ddca59efbc6e5d7e199691c2c67cc88c2e8 100644 (file)
 
 #define XMPP_OID "1.3.6.1.5.5.7.8.5"
 #define KRB5_PRINCIPAL_OID "1.3.6.1.5.2.2"
+#define MSUSER_PRINCIPAL_NAME_OID "1.3.6.1.4.1.311.20.2.3"
 #define PKIX1_RSA_PSS_MGF1_OID "1.2.840.113549.1.1.8"
 
 #define GOST28147_89_OID "1.2.643.2.2.21"
index 6c1546ea81eca7a8c861055808127b956370e670..ba37674042d071e25d9c0901e073d7fac25e398b 100644 (file)
@@ -96,7 +96,8 @@ static int validate_name_constraints_node(gnutls_x509_subject_alt_name_t type,
 {
        if (type != GNUTLS_SAN_DNSNAME && type != GNUTLS_SAN_RFC822NAME &&
                type != GNUTLS_SAN_DN && type != GNUTLS_SAN_URI &&
-               type != GNUTLS_SAN_IPADDRESS) {
+               type != GNUTLS_SAN_IPADDRESS && 
+               type != GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL) {
                return gnutls_assert_val(GNUTLS_E_X509_UNKNOWN_SAN);
        }
 
@@ -138,6 +139,28 @@ int _gnutls_extract_name_constraints(asn1_node c2, const char *vstr,
                        break;
                }
 
+               if (type == GNUTLS_SAN_OTHERNAME) {
+                       gnutls_datum_t oid = { NULL, 0 };
+                        gnutls_datum_t parsed_othername = { NULL, 0 };
+                        ret = _gnutls_parse_general_name2(c2, tmpstr, -1, &oid, &type, 1);
+                        if(ret < 0) {
+                                gnutls_assert();
+                                goto cleanup;
+                        }
+
+                        ret = gnutls_x509_othername_to_virtual((char*)oid.data, &tmp, &type,
+                                &parsed_othername);
+                        if(ret < 0) {
+                                gnutls_assert();
+                                goto cleanup;
+                        }
+
+                       gnutls_free(oid.data);
+                       gnutls_free(tmp.data);
+
+                        memcpy(&tmp, &parsed_othername, sizeof(gnutls_datum_t));
+               }
+
                ret = validate_name_constraints_node(type, &tmp);
                if (ret < 0) {
                        gnutls_assert();
index 30ca7f4664fc455ea122d92bd5ebab4614cc0b52..2ec288c933596b304634eb75047192b201014b6a 100644 (file)
@@ -108,6 +108,7 @@ print_name(gnutls_buffer_st *str, const char *prefix, unsigned type, gnutls_datu
 
        if ((type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_OTHERNAME_XMPP
             || type == GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL
+            || type == GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL
             || type == GNUTLS_SAN_RFC822NAME
             || type == GNUTLS_SAN_URI) && sname != NULL && strlen(sname) != name->size) {
                adds(str,
@@ -156,6 +157,10 @@ print_name(gnutls_buffer_st *str, const char *prefix, unsigned type, gnutls_datu
                addf(str,  _("%sKRB5Principal: %.*s\n"), prefix, name->size, NON_NULL(name->data));
                break;
 
+       case GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL:
+               addf(str, _("%sUser Principal Name: %.*s\n"), prefix, name->size, NON_NULL(name->data));
+               break;
+
        default:
                addf(str,  _("%sUnknown name: "), prefix);
                _gnutls_buffer_hexprint(str, name->data, name->size);
@@ -761,6 +766,8 @@ print_key_purpose(gnutls_buffer_st * str, const char *prefix, gnutls_datum_t *de
                        addf(str, _("%s\t\t\tOCSP signing.\n"), prefix);
                else if (strcmp(p, GNUTLS_KP_IPSEC_IKE) == 0)
                        addf(str, _("%s\t\t\tIpsec IKE.\n"), prefix);
+               else if (strcmp(p, GNUTLS_KP_MS_SMART_CARD_LOGON) == 0)
+                       addf(str, _("%s\t\t\tSmart Card Logon.\n"), prefix);
                else if (strcmp(p, GNUTLS_KP_ANY) == 0)
                        addf(str, _("%s\t\t\tAny purpose.\n"), prefix);
                else
index d2adc4e25eef524e05006262ddeae4887ee3c924..e62bd4a0382436017739da34c27bc66539f20d6e 100644 (file)
@@ -40,6 +40,9 @@ int san_othername_to_virtual(const char *oid, size_t size)
                else if ((unsigned) size == (sizeof(KRB5_PRINCIPAL_OID)-1)
                    && memcmp(oid, KRB5_PRINCIPAL_OID, sizeof(KRB5_PRINCIPAL_OID)-1) == 0)
                        return GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL;
+               else if ((unsigned) size == (sizeof(MSUSER_PRINCIPAL_NAME_OID)-1)
+                   && memcmp(oid, MSUSER_PRINCIPAL_NAME_OID, sizeof(MSUSER_PRINCIPAL_NAME_OID)-1) == 0)
+                       return GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL;
        }
 
        return GNUTLS_SAN_OTHERNAME;
@@ -53,6 +56,8 @@ const char * virtual_to_othername_oid(unsigned type)
                        return XMPP_OID;
                case GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL:
                        return KRB5_PRINCIPAL_OID;
+               case GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL:
+                       return MSUSER_PRINCIPAL_NAME_OID;
                default:
                        return NULL;
        }
@@ -171,6 +176,15 @@ int gnutls_x509_othername_to_virtual(const char *oid,
                                return ret;
                        }
                        return 0;
+               case GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL:
+                       ret = _gnutls_x509_decode_string
+                                   (ASN1_ETYPE_UTF8_STRING, othername->data,
+                                    othername->size, virt, 0);
+                       if (ret < 0) {
+                               gnutls_assert();
+                               return ret;
+                       }
+                       return 0;
                default:
                        return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
        }
index 7a63d3e3679334a023fb40e47a2754812393b876..490e8bdba07a5e1879698eeee6e9df4e1a1d08b3 100644 (file)
@@ -1793,10 +1793,14 @@ _gnutls_parse_general_name2(asn1_node src, const char *src_name,
                } else {
                        char oid[MAX_OID_SIZE];
 
-                       if (src_name[0] != 0)
+                       if (src_name[0] != 0 && seq != -1)
                                snprintf(nptr, sizeof(nptr),
                                         "%s.?%d.otherName.type-id",
                                         src_name, seq);
+                       else if (src_name[0] != 0)
+                               snprintf(nptr, sizeof(nptr),
+                                        "%s.otherName.type-id",
+                                        src_name);
                        else
                                snprintf(nptr, sizeof(nptr),
                                         "?%d.otherName.type-id", seq);
index cec0a4e88021ec9df7065027919abf5d1980c69d..13fb94e88bf99925566d9fe69d6caec8c6b5c0cf 100644 (file)
@@ -230,7 +230,8 @@ ctests += mini-record-2 simple gnutls_hmac_fast set_pkcs12_cred cert certuniquei
         sign-verify-newapi sign-verify-deterministic iov aead-cipher-vec \
         tls13-without-timeout-func buffer status-request-revoked \
         set_x509_ocsp_multi_cli kdf-api keylog-func handshake-write \
-        x509cert-dntypes id-on-xmppAddr tls13-compat-mode ciphersuite-name
+        x509cert-dntypes id-on-xmppAddr tls13-compat-mode ciphersuite-name \
+        x509-upnconstraint
 
 ctests += tls-channel-binding
 
diff --git a/tests/x509-upnconstraint.c b/tests/x509-upnconstraint.c
new file mode 100644 (file)
index 0000000..a25e06b
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2022 Brian Wickman
+ *
+ * Author: Brian Wickman
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "utils.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <gnutls/x509-ext.h>
+
+/* Test that UPN OTHERNAME constraints in a CA certificate 
+ * are parsed correctly
+ *
+ * Test that a leaf certificate with a DNSName validates correctly
+ * when issued by a CA with UPN OTHERNAME constraints (Issue 1132)
+ * (UPN == User Principal Name - used in Active Directory
+ * environments using smartcards for authentication)
+ */
+
+void verify_upn_constraints(gnutls_x509_name_constraints_t);
+void verify_non_upn_leaf(gnutls_x509_name_constraints_t);
+
+static const char _domaincontroller[] = {
+       "-----BEGIN CERTIFICATE-----\n"
+       "MIIEqTCCA5GgAwIBAgITQAAAAAPX0eQxgcZpHAAAAAAAAzANBgkqhkiG9w0BAQsF\n"
+       "ADA0MRUwEwYDVQQKEwxFeGFtcGxlIEluYy4xGzAZBgNVBAMTEkV4YW1wbGUgQ29y\n"
+       "cCBBRCBDQTAeFw0yMjA0MTIxNjUzMTFaFw0yNzA0MTExNjUzMTFaMCIxIDAeBgNV\n"
+       "BAMTF2V4YW1wbGVkYzAxLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC\n"
+       "AQ8AMIIBCgKCAQEAtnYFOqZas9U9GX87w2bvyQh6l3fWJ83JHEHAwP11j9dQu/sa\n"
+       "qgMYr/OqH+5tCvsDLt9sI35RCuF+6San3P1m56G+iYaawE46UrbHSYC4PyhinOXx\n"
+       "X3xXzaxjTDYhz46Fvfmoqa732zPYG3QQplPsjQbRx96iXOSkdWt8g4mbTJ/eyYdG\n"
+       "uXt1mlvL+USz5b39trOgSgTC60cdneBrQsBh7o80rHvaprvjTY5mHS7JNHcsr9Hs\n"
+       "xjOOq9t3LdWehXYshINZ6ChxaHipbBUF+0CTvwJW8wvQtSV6MYDl+cbS/47OwJG0\n"
+       "OXJxFVQofJWNi4/IrTC42d3fyEWA2ZnP898GeQIDAQABo4IBxDCCAcAwPQYJKwYB\n"
+       "BAGCNxUHBDAwLgYmKwYBBAGCNxUIg/iOToSq0GWEhZMhhZ3KIoKY1VocgufIbYTY\n"
+       "+3sCAWQCAQIwMgYDVR0lBCswKQYHKwYBBQIDBQYKKwYBBAGCNxQCAgYIKwYBBQUH\n"
+       "AwEGCCsGAQUFBwMCMA4GA1UdDwEB/wQEAwIFoDBABgkrBgEEAYI3FQoEMzAxMAkG\n"
+       "BysGAQUCAwUwDAYKKwYBBAGCNxQCAjAKBggrBgEFBQcDATAKBggrBgEFBQcDAjAd\n"
+       "BgNVHQ4EFgQUjaBu4CsVk5gng+ACWTSqsj1gmVQwNAYDVR0RBC0wK4IXZXhhbXBs\n"
+       "ZWRjMDEuZXhhbXBsZS5jb22CEGxkYXAuZXhhbXBsZS5jb20wHwYDVR0jBBgwFoAU\n"
+       "aRL34OyTRJUSVVfxMiMjBFHk/WowOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL3Br\n"
+       "aS5leGFtcGxlLmNvbS9jZHAvRXhhbXBsZUFEQ0EuY3JsMEYGCCsGAQUFBwEBBDow\n"
+       "ODA2BggrBgEFBQcwAoYqaHR0cDovL3BraS5leGFtcGxlLmNvbS9haWEvRXhhbXBs\n"
+       "ZUFEQ0EuY2VyMA0GCSqGSIb3DQEBCwUAA4IBAQCKr0WQYujcyUOUZp63i27dMihf\n"
+       "z+WKd2G+dyGzmNTabFlZSfquFo+MWmSM04UOEYS45tyFZhWEXXaz4OfilelKy5XI\n"
+       "tiZRGDvzNzxfb7GQSWDO1mxLHW2yEH+1Cyu/Km0PRhDl1Vy0DFyrdGh/w7qTM7eG\n"
+       "BjD0bBtk9/M58IYlnzx7CM53CRGhPHUygontN1vbWf42gDdu+5d+tnls86gTzuRs\n"
+       "su4BReayHU9aFqorWhvxCQhgnLx98Ei2BsJe5nbSzjVA5ZhPcL9WDC76aDPEDaZg\n"
+       "GnNu9kZJV/UrCaulu0COhJfNocd/LWXZbUStUCenRX01GHCP+4mNmPLJkVh2\n"
+       "-----END CERTIFICATE-----"
+};
+
+static const char _issuingca[] = {
+/* The intermediate CA with name constraints */
+       "-----BEGIN CERTIFICATE-----\n"
+       "MIIE0jCCA7qgAwIBAgITLgAAAAK9f34egj9VJAAAAAAAAjANBgkqhkiG9w0BAQsF\n"
+       "ADA2MRUwEwYDVQQKEwxFeGFtcGxlIEluYy4xHTAbBgNVBAMTFEV4YW1wbGUgQ29y\n"
+       "cCBSb290IENBMCAXDTIyMDQxMjE2Mzk0M1oYDzIwNjcwNDEyMTY0OTQzWjA0MRUw\n"
+       "EwYDVQQKEwxFeGFtcGxlIEluYy4xGzAZBgNVBAMTEkV4YW1wbGUgQ29ycCBBRCBD\n"
+       "QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALs2TqehwJfMyrU77MRv\n"
+       "4jgwgnsruZMexMGwT6A5oxdjKNhyXnsdiYiH3nFEgrHSCOAxgoCDJYlDLn0jZYdS\n"
+       "3j7hMrhzAwHzwUgTrruHaTZ2tShxbfvUAGuuOroSVB4+XzS22RKdgh7g1cv3scWI\n"
+       "62M2vfV8iBpehD5xhmqfu2Z9ChNTR32HLHdFdsMFuS+t0Zktszk1qE9AClFa7ttr\n"
+       "VKgOyEmjgXlhX/Qld4zgCvxvI/jMPbEKrU2ZFeRV160vGaraAVjF0Oxe9TFH9fLZ\n"
+       "E+ERghmfdzzbNOXikgExrsveALNRsbTyIhKmEDRGMN/y12htghHvBamwGDt/gj9q\n"
+       "3fECAwEAAaOCAdcwggHTMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRpEvfg\n"
+       "7JNElRJVV/EyIyMEUeT9ajAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNV\n"
+       "HQ8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBQlQb5lkuye\n"
+       "IfoJIi/ctatOBUANSDA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vcGtpLmV4YW1w\n"
+       "bGUuY29tL2NkcC9FeGFtcGxlUm9vdC5jcmwwggEEBgNVHR4BAf8EgfkwgfagajAN\n"
+       "ggtleGFtcGxlLmNvbTAOggwuZXhhbXBsZS5jb20wCYIHRVhBTVBMRTAeoBwGCisG\n"
+       "AQQBgjcUAgOgDgwMQGV4YW1wbGUuY29tMB6gHAYKKwYBBAGCNxQCA6AODAwuZXhh\n"
+       "bXBsZS5jb22hgYcwF4IVc3ViZG9tYWluLmV4YW1wbGUuY29tMBiCFi5zdWJkb21h\n"
+       "aW4uZXhhbXBsZS5jb20wKKAmBgorBgEEAYI3FAIDoBgMFkBzdWJkb21haW4uZXhh\n"
+       "bXBsZS5jb20wKKAmBgorBgEEAYI3FAIDoBgMFi5zdWJkb21haW4uZXhhbXBsZS5j\n"
+       "b20wDQYJKoZIhvcNAQELBQADggEBAG+gD/ZNEaoukBt/U+7tGOwx5bTAdNChYZEU\n"
+       "Wzt5XoJ0ZgClfgtKk/hmDxPsUEVOzaYEtUrj8V0qJun5YwEzZsZbHAkbkTOcQ2tC\n"
+       "5Jv7czs0IYrSCJIgz7PdNSxTaXyCpipzUvSdZxQj3Bjj+MiYiReEwxhAb6bI/D8h\n"
+       "HXk9T5iHiw9f7P6ZTBvx5keUjAePO8sc0CtefOIH+tyRY1oEHAzMSDzqhpeZDAtM\n"
+       "N93KZkhnx/kmQhqLXhrck9Ubozw++e2iP83bTojTFSodRiKWPtUKOHAlPvIWQURc\n"
+       "YP0dQUsv1tMnNjJgA7COp1+mmqfEUVQqmBwRbJ26ve2iwS/SAgI=\n"
+       "-----END CERTIFICATE-----"
+};
+
+const unsigned char example3[] = "@example.com";
+const unsigned char example4[] = ".example.com";
+const unsigned char subdomain2[] = "@subdomain.example.com";
+const unsigned char subdomain3[] = ".subdomain.example.com";
+
+void verify_upn_constraints(gnutls_x509_name_constraints_t name_constraints)
+{
+       int ret = 0;
+       unsigned int type = 0;
+       gnutls_datum_t constraint = { NULL, 0 };
+       ret = gnutls_x509_name_constraints_get_permitted(name_constraints, 3,
+                                                        &type, &constraint);
+       if (ret < 0) {
+               fail("Error getting permitted constraint line %d: %s\n",
+                    __LINE__, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       if (type != GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL) {
+               fail("Error permitted constraint 3 is not UPN line: %d Found: %u\n", __LINE__, type);
+               exit(1);
+       }
+
+       if ((constraint.size != sizeof(example3) - 1) ||
+           memcmp(constraint.data, example3, sizeof(example3) - 1) != 0) {
+               fail("Error permitted constraint 3 was %s expected %s line: %d\n", constraint.data, example3, __LINE__);
+               exit(1);
+       }
+
+       ret = gnutls_x509_name_constraints_get_permitted(name_constraints, 4,
+                                                        &type, &constraint);
+       if (ret < 0) {
+               fail("Error getting permitted constraint line %d: %s\n",
+                    __LINE__, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       if (type != GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL) {
+               fail("Error permitted constraint 4 is not UPN line: %d Found: %u\n", __LINE__, type);
+               exit(1);
+       }
+
+       if ((constraint.size != sizeof(example4) - 1) ||
+           memcmp(constraint.data, example4, sizeof(example4) - 1) != 0) {
+               fail("Error permitted constraint 4 was %s expected %s line: %d\n", constraint.data, example4, __LINE__);
+               exit(1);
+       }
+
+       ret = gnutls_x509_name_constraints_get_excluded(name_constraints, 2,
+                                                       &type, &constraint);
+       if (ret < 0) {
+               fail("Error getting excluded constraint line %d: %s\n",
+                    __LINE__, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       if (type != GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL) {
+               fail("Error excluded constraint 2 is not UPN line: %d Found %u\n", __LINE__, type);
+               exit(1);
+       }
+
+       if ((constraint.size != sizeof(subdomain2) - 1) ||
+           memcmp(constraint.data, subdomain2, sizeof(subdomain2) - 1) != 0) {
+               fail("Error excluded constraint 2 was %s expected %s line: %d\n", constraint.data, subdomain2, __LINE__);
+               exit(1);
+       }
+
+       ret = gnutls_x509_name_constraints_get_excluded(name_constraints, 3,
+                                                       &type, &constraint);
+       if (ret < 0) {
+               fail("Error getting excluded constraint line %d: %s\n",
+                    __LINE__, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       if (type != GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL) {
+               fail("Error excluded constraint 3 is not UPN line: %d Found %u\n", __LINE__, type);
+               exit(1);
+       }
+
+       if ((constraint.size != sizeof(subdomain3) - 1) ||
+           memcmp(constraint.data, subdomain3, sizeof(subdomain3) - 1) != 0) {
+               fail("Error excluded constraint 3 was %s expected %s line: %d\n", constraint.data, subdomain3, __LINE__);
+               exit(1);
+       }
+}
+
+void verify_non_upn_leaf(gnutls_x509_name_constraints_t name_constraints)
+{
+       // This test specifically checks for resolution of issue 1132
+       int ret = 0;
+       gnutls_x509_crt_t domaincontroller;
+       gnutls_datum_t domaincontroller_datum = { (void *)_domaincontroller,
+               sizeof(_domaincontroller) - 1
+       };
+
+       gnutls_x509_crt_init(&domaincontroller);
+
+       ret = gnutls_x509_crt_import(domaincontroller, &domaincontroller_datum,
+                                    GNUTLS_X509_FMT_PEM);
+       if (ret < 0) {
+               fail("Error importing domain controller cert line %d: %s\n",
+                    __LINE__, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       ret = gnutls_x509_name_constraints_check_crt(name_constraints,
+                                                    GNUTLS_SAN_DNSNAME,
+                                                    domaincontroller);
+       if (ret < 0) {
+               fail("Error failed to verify leaf cert against constraints line: %d\n", __LINE__);
+               exit(1);
+       }
+
+       gnutls_x509_crt_deinit(domaincontroller);
+}
+
+void doit(void)
+{
+       int ret;
+       unsigned int critical = 0;
+       gnutls_x509_crt_t issuingca;
+       gnutls_datum_t issuingca_datum =
+           { (void *)_issuingca, sizeof(_issuingca) - 1 };
+
+       gnutls_x509_crt_init(&issuingca);
+
+       ret = gnutls_x509_crt_import(issuingca, &issuingca_datum,
+                                    GNUTLS_X509_FMT_PEM);
+       if (ret < 0) {
+               fail("Error importing issuing CA line %d: %s\n", __LINE__,
+                    gnutls_strerror(ret));
+               exit(1);
+       }
+
+       gnutls_x509_name_constraints_t name_constraints = NULL;
+
+       ret = gnutls_x509_name_constraints_init(&name_constraints);
+       if (ret < 0) {
+               fail("Error initializing constraints structure line %d: %s\n",
+                    __LINE__, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       ret =
+           gnutls_x509_crt_get_name_constraints(issuingca, name_constraints, 0,
+                                                &critical);
+       if (ret < 0) {
+               // Failure here is potentially a regression to issue 1132 behavior
+               fail("Error loading constraints line: %d\n", __LINE__);
+               exit(1);
+       }
+
+       verify_upn_constraints(name_constraints);
+
+       verify_non_upn_leaf(name_constraints);
+
+       gnutls_x509_name_constraints_deinit(name_constraints);
+       gnutls_x509_crt_deinit(issuingca);
+
+       success("UPN constraints tests completed succesfully\n");
+}
+
+/* The following cert is the root CA that signed the intermediate CA used in
+ * the tests up above. While it wasn't needed in these tests, it is included
+ * here in case it becomes useful in the future:
+ *
+-----BEGIN CERTIFICATE-----
+MIIDSTCCAjGgAwIBAgIQKpl3VjKWEKlMf9Nx+omsZDANBgkqhkiG9w0BAQsFADA2
+MRUwEwYDVQQKEwxFeGFtcGxlIEluYy4xHTAbBgNVBAMTFEV4YW1wbGUgQ29ycCBS
+b290IENBMCAXDTIyMDQxMjE1NTkyMloYDzIwNzIwNDEyMTYwOTIyWjA2MRUwEwYD
+VQQKEwxFeGFtcGxlIEluYy4xHTAbBgNVBAMTFEV4YW1wbGUgQ29ycCBSb290IENB
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Stt+MibOCQO69wtINEM
+9cdxjQyk2WMKzZflAOmi5lFNUmNsxGBQGcVk8dlyUwiWGUlGshUvBBcEGgnxKnO+
+S465gyS6fcFfrpX7B/CQWv2/m0n7rdJ65TnB2vRct2Ni/6AjgZLSJXxwjXiuH72Z
+k37vpxY4B6mOCe2XjUu2J8DhG9K4FatzeqsUgpvbiXdO/hD1oWQbFRVOeHAdipBC
++KH6qOL4g7V3V1gW99DuR/ZyJqU9uRrBe8CyP1PxcSUySfFx9hhTB5hSufiCDuR3
+KRKTyaXZ/1l0e2MY3wKig/PujBhYdLTLoErnYN6ccP98jBZIHMacE43e4WUCI2Ld
+WQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQUJUG+ZZLsniH6CSIv3LWrTgVADUgwEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI
+hvcNAQELBQADggEBAGg86wjyMMGKZ0VSLko7AdNTqmD5jkamol7zPFbjuX8Cc3IQ
+KyQkhkrA3v6bDbau8axLeqs40TLO12f3LNRGMcVNN1I8SbCEN3IvX6W0wLkiVxvV
++lVKCuCb2JedmXjOHHkkm4xhlsCZipA3Pz3cOXeIt2DLnoY7G6i7N5cZoAXgxQ3V
+jjnsUINFWuwBDbjmLA+H9eGIyAQSXkWPBLI6K7jOV8V3FLv1ACkW3K9agJCcx2uO
+kdBFhRm4kl2U5HB/qOZ685ouNQj6kz9xgykOxiabgellz846uUIfMBxsQaoU1dAX
+vO7vJHxoQOJiTc9u+eOSFe+eFIeLlCHLz6k59tE=
+-----END CERTIFICATE-----
+*/