Print this page
6429 SMB domain join doesn't work with libreSSL

@@ -29,10 +29,11 @@
  */
 
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved.
+ * Copyright 2017 RackTop Systems.
  */
 
 #include <errno.h>
 #include <string.h>
 #include <stdio.h>

@@ -367,14 +368,10 @@
     0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
     0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 };
 
-/* Solaris Kerberos */
-static k5_mutex_t oids_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
-static int pkinit_oids_refs = 0;
-
 krb5_error_code
 pkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx) {
 
     krb5_error_code retval = ENOMEM;
     pkinit_plg_crypto_context ctx = NULL;

@@ -505,77 +502,47 @@
 }
 
 static krb5_error_code
 pkinit_init_pkinit_oids(pkinit_plg_crypto_context ctx)
 {
-    krb5_error_code retval = ENOMEM;
-    int nid = 0;
+    ctx->id_pkinit_san = OBJ_txt2obj("1.3.6.1.5.2.2", 1);
+    if (ctx->id_pkinit_san == NULL)
+        return ENOMEM;
 
-    /*
-     * If OpenSSL already knows about the OID, use the
-     * existing definition. Otherwise, create an OID object.
-     */
-    #define CREATE_OBJ_IF_NEEDED(oid, vn, sn, ln) \
-        nid = OBJ_txt2nid(oid); \
-        if (nid == NID_undef) { \
-            nid = OBJ_create(oid, sn, ln); \
-            if (nid == NID_undef) { \
-                pkiDebug("Error creating oid object for '%s'\n", oid); \
-                goto out; \
-            } \
-        } \
-        ctx->vn = OBJ_nid2obj(nid);
+    ctx->id_pkinit_authData = OBJ_txt2obj("1.3.6.1.5.2.3.1", 1);
+    if (ctx->id_pkinit_authData == NULL)
+        return ENOMEM;
     
-    /* Solaris Kerberos */
-    retval = k5_mutex_lock(&oids_mutex);
-    if (retval != 0)
-        goto out;
+    ctx->id_pkinit_DHKeyData = OBJ_txt2obj("1.3.6.1.5.2.3.2", 1);
+    if (ctx->id_pkinit_DHKeyData == NULL)
+        return ENOMEM;
 
-    CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.2", id_pkinit_san,
-                         "id-pkinit-san", "KRB5PrincipalName");
+    ctx->id_pkinit_rkeyData = OBJ_txt2obj("1.3.6.1.5.2.3.3", 1);
+    if (ctx->id_pkinit_rkeyData == NULL)
+        return ENOMEM;
 
-    CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.1", id_pkinit_authData,
-                         "id-pkinit-authdata", "PKINIT signedAuthPack");
+    ctx->id_pkinit_KPClientAuth = OBJ_txt2obj("1.3.6.1.5.2.3.4", 1);
+    if (ctx->id_pkinit_KPClientAuth == NULL)
+        return ENOMEM;
 
-    CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.2", id_pkinit_DHKeyData,
-                         "id-pkinit-DHKeyData", "PKINIT dhSignedData");
+    ctx->id_pkinit_KPKdc = OBJ_txt2obj("1.3.6.1.5.2.3.5", 1);
+    if (ctx->id_pkinit_KPKdc == NULL)
+        return ENOMEM;
 
-    CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.3", id_pkinit_rkeyData,
-                         "id-pkinit-rkeyData", "PKINIT encKeyPack");
+    ctx->id_ms_kp_sc_logon = OBJ_txt2obj("1.3.6.1.4.1.311.20.2.2", 1);
+    if (ctx->id_ms_kp_sc_logon == NULL)
+        return ENOMEM;
 
-    CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.4", id_pkinit_KPClientAuth,
-                         "id-pkinit-KPClientAuth", "PKINIT Client EKU");
+    ctx->id_ms_san_upn = OBJ_txt2obj("1.3.6.1.4.1.311.20.2.3", 1);
+    if (ctx->id_ms_san_upn == NULL)
+        return ENOMEM;
 
-    CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.5", id_pkinit_KPKdc,
-                         "id-pkinit-KPKdc", "KDC EKU");
+    ctx->id_kp_serverAuth = OBJ_txt2obj("1.3.6.1.5.5.7.3.1", 1);
+    if (ctx->id_kp_serverAuth == NULL)
+        return ENOMEM;
 
-#if 0
-    CREATE_OBJ_IF_NEEDED("1.2.840.113549.1.7.1", id_pkinit_authData9,
-                         "id-pkcs7-data", "PKCS7 data");
-#else
-    /* See note in pkinit_pkcs7type2oid() */
-    ctx->id_pkinit_authData9 = NULL;
-#endif
-
-    CREATE_OBJ_IF_NEEDED("1.3.6.1.4.1.311.20.2.2", id_ms_kp_sc_logon,
-                         "id-ms-kp-sc-logon EKU", "Microsoft SmartCard Login EKU");
-
-    CREATE_OBJ_IF_NEEDED("1.3.6.1.4.1.311.20.2.3", id_ms_san_upn,
-                         "id-ms-san-upn", "Microsoft Universal Principal Name");
-
-    CREATE_OBJ_IF_NEEDED("1.3.6.1.5.5.7.3.1", id_kp_serverAuth,
-                         "id-kp-serverAuth EKU", "Server Authentication EKU");
-
-    /* Success */
-    retval = 0;
-    
-    pkinit_oids_refs++;
-    /* Solaris Kerberos */
-    k5_mutex_unlock(&oids_mutex);
-
-out:
-    return retval;
+    return 0;
 }
 
 static krb5_error_code
 get_cert(char *filename, X509 **retcert)
 {

@@ -650,17 +617,19 @@
 static void
 pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx)
 {
     if (ctx == NULL)
         return;
-
-    /* Only call OBJ_cleanup once! */
-    /* Solaris Kerberos: locking */
-    k5_mutex_lock(&oids_mutex);
-    if (--pkinit_oids_refs == 0)
-        OBJ_cleanup();
-    k5_mutex_unlock(&oids_mutex);
+    ASN1_OBJECT_free(ctx->id_pkinit_san);
+    ASN1_OBJECT_free(ctx->id_pkinit_authData);
+    ASN1_OBJECT_free(ctx->id_pkinit_DHKeyData);
+    ASN1_OBJECT_free(ctx->id_pkinit_rkeyData);
+    ASN1_OBJECT_free(ctx->id_pkinit_KPClientAuth);
+    ASN1_OBJECT_free(ctx->id_pkinit_KPKdc);
+    ASN1_OBJECT_free(ctx->id_ms_kp_sc_logon);
+    ASN1_OBJECT_free(ctx->id_ms_san_upn);
+    ASN1_OBJECT_free(ctx->id_kp_serverAuth);
 }
 
 static krb5_error_code
 pkinit_init_dh_params(pkinit_plg_crypto_context plgctx)
 {

@@ -834,10 +803,59 @@
     id_cryptoctx->prompter_data = prompter_data;
 
     return 0;
 }
 
+/* Create a CMS ContentInfo of type oid containing the octet string in data. */
+static krb5_error_code
+create_contentinfo(krb5_context context,
+                   ASN1_OBJECT *oid,
+                   unsigned char *data,
+                   size_t data_len,
+                   PKCS7 **p7_out)
+{
+    PKCS7 *p7 = NULL;
+    ASN1_OCTET_STRING *ostr = NULL;
+
+    *p7_out = NULL;
+
+    ostr = ASN1_OCTET_STRING_new();
+    if (ostr == NULL)
+        goto oom;
+    if (!ASN1_OCTET_STRING_set(ostr, (unsigned char *)data, data_len))
+        goto oom;
+
+    p7 = PKCS7_new();
+    if (p7 == NULL)
+        goto oom;
+    p7->type = OBJ_dup(oid);
+    if (p7->type == NULL)
+        goto oom;
+
+    if (OBJ_obj2nid(oid) == NID_pkcs7_data) {
+        /* Draft 9 uses id-pkcs7-data for signed data.  For this type OpenSSL
+         * expects an octet string in d.data. */
+        p7->d.data = ostr;
+    } else {
+        p7->d.other = ASN1_TYPE_new();
+        if (p7->d.other == NULL)
+            goto oom;
+        p7->d.other->type = V_ASN1_OCTET_STRING;
+        p7->d.other->value.octet_string = ostr;
+    }
+
+    *p7_out = p7;
+    return 0;
+
+oom:
+    if (ostr != NULL)
+        ASN1_OCTET_STRING_free(ostr);
+    if (p7 != NULL)
+        PKCS7_free(p7);
+    return ENOMEM;
+}
+
 /* ARGSUSED */
 krb5_error_code
 cms_signeddata_create(krb5_context context,
                       pkinit_plg_crypto_context plg_cryptoctx,
                       pkinit_req_crypto_context req_cryptoctx,

@@ -853,11 +871,10 @@
     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
     PKCS7  *p7 = NULL, *inner_p7 = NULL;
     PKCS7_SIGNED *p7s = NULL;
     PKCS7_SIGNER_INFO *p7si = NULL;
     unsigned char *p;
-    ASN1_TYPE *pkinit_data = NULL;
     STACK_OF(X509) * cert_stack = NULL;
     ASN1_OCTET_STRING *digest_attr = NULL;
     EVP_MD_CTX ctx, ctx2;
     const EVP_MD *md_tmp = NULL;
     unsigned char md_data[EVP_MAX_MD_SIZE], md_data2[EVP_MAX_MD_SIZE];

@@ -869,11 +886,11 @@
     X509_ALGOR *alg = NULL;
     ASN1_OCTET_STRING *digest = NULL;
     unsigned int alg_len = 0, digest_len = 0;
     unsigned char *y = NULL, *alg_buf = NULL, *digest_buf = NULL;
     X509 *cert = NULL;
-    ASN1_OBJECT *oid = NULL;
+    ASN1_OBJECT *oid = NULL, *oid_copy;
 
     /* Solaris Kerberos */
     if (signed_data == NULL)
         return EINVAL;
 

@@ -994,12 +1011,15 @@
         ASN1_OCTET_STRING_set(digest_attr, md_data, (int)md_len);
         PKCS7_add_signed_attribute(p7si, NID_pkcs9_messageDigest,
                                    V_ASN1_OCTET_STRING, (char *) digest_attr);
 
         /* create a content-type attr */
+        oid_copy = OBJ_dup(oid);
+        if (oid_copy == NULL)
+                goto cleanup2;
         PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType, 
-                                   V_ASN1_OBJECT, oid);
+                                   V_ASN1_OBJECT, oid_copy);
 
         /* create the signature over signed attributes. get DER encoded value */
         /* This is the place where smartcard signature needs to be calculated */
         sk = p7si->auth_attr;
         alen = ASN1_item_i2d((ASN1_VALUE *) sk, &abuf,

@@ -1092,30 +1112,11 @@
     /* adder signer_info to pkcs7 signed */
     if (!PKCS7_add_signer(p7, p7si))
         goto cleanup2;
 
     /* start on adding data to the pkcs7 signed */
-    if ((inner_p7 = PKCS7_new()) == NULL)
-        goto cleanup2;
-    if ((pkinit_data = ASN1_TYPE_new()) == NULL)
-        goto cleanup2;
-    pkinit_data->type = V_ASN1_OCTET_STRING;
-    if ((pkinit_data->value.octet_string = ASN1_OCTET_STRING_new()) == NULL)
-        goto cleanup2;
-    if (!ASN1_OCTET_STRING_set(pkinit_data->value.octet_string, data,
-                               (int)data_len)) {
-        unsigned long err = ERR_peek_error();
-        retval = KRB5KDC_ERR_PREAUTH_FAILED;
-        krb5_set_error_message(context, retval, "%s\n",
-                               ERR_error_string(err, NULL));
-        pkiDebug("failed to add pkcs7 data\n");
-        goto cleanup2;
-    }
-
-    if (!PKCS7_set0_type_other(inner_p7, OBJ_obj2nid(oid), pkinit_data))
-        goto cleanup2;
-
+    retval = create_contentinfo(context, oid, data, data_len, &inner_p7);
     if (p7s->contents != NULL)
         PKCS7_free(p7s->contents);
     p7s->contents = inner_p7;
 
     *signed_data_len = i2d_PKCS7(p7, NULL);

@@ -1222,11 +1223,10 @@
 #ifdef DEBUG_ASN1
     print_buffer_bin(signed_data, signed_data_len,
                      "/tmp/client_received_pkcs7_signeddata");
 #endif
 
-    /* Do this early enough to create the shadow OID for pkcs7-data if needed */
     oid = pkinit_pkcs7type2oid(plgctx, cms_msg_type);
     if (oid == NULL)
         goto cleanup;
 
     /* decode received PKCS7 message */

@@ -3125,35 +3125,15 @@
 }
 
 static ASN1_OBJECT *
 pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx, int pkcs7_type)
 {
-    int nid;
-
     switch (pkcs7_type) {
         case CMS_SIGN_CLIENT:
             return cryptoctx->id_pkinit_authData;
         case CMS_SIGN_DRAFT9:
-            /*
-             * Delay creating this OID until we know we need it.
-             * It shadows an existing OpenSSL oid.  If it
-             * is created too early, it breaks things like
-             * the use of pkcs12 (which uses pkcs7 structures).
-             * We need this shadow version because our code
-             * depends on the "other" type to be unknown to the
-             * OpenSSL code.
-             */ 
-            if (cryptoctx->id_pkinit_authData9 == NULL) {
-                pkiDebug("%s: Creating shadow instance of pkcs7-data oid\n",
-                         __FUNCTION__);
-                nid = OBJ_create("1.2.840.113549.1.7.1", "id-pkcs7-data",
-                                 "PKCS7 data");
-                if (nid == NID_undef)
-                    return NULL;
-                cryptoctx->id_pkinit_authData9 = OBJ_nid2obj(nid);
-            }
-            return cryptoctx->id_pkinit_authData9;
+            return OBJ_nid2obj(NID_pkcs7_data);
         case CMS_SIGN_SERVER:
             return cryptoctx->id_pkinit_DHKeyData;
         case CMS_ENVEL_SERVER:
             return cryptoctx->id_pkinit_rkeyData;
         default: