Negotiate seems to be working JDK-8199569-branch
authorweijun
Wed, 16 May 2018 22:45:34 +0800
branchJDK-8199569-branch
changeset 56562 94c6b9e7df00
parent 56555 0cd4e27a12cf
child 56574 3813511b3d24
Negotiate seems to be working
src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp
--- a/src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp	Tue May 15 12:20:42 2018 +0800
+++ b/src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp	Wed May 16 22:45:34 2018 +0800
@@ -53,6 +53,7 @@
 #define PP(fmt, ...) \
         fprintf(stdout, "SSPI (%ld): ", __LINE__); \
         fprintf(stdout, fmt, ##__VA_ARGS__); \
+        fprintf(stdout, "\n"); \
         fflush(stdout)
 #else
 #define SEC_SUCCESS(Status) ((Status) >= 0)
@@ -71,8 +72,8 @@
         (char)0x2a, (char)0x86, (char)0x48, (char)0x86, (char)0xf7, (char)0x12,
         (char)0x01, (char)0x02, (char)0x01, (char)0x04};
 
-// gss_name_t is SecPkgCredentials_Names*
-// gss_cred_id_t is CredHandle*
+// gss_name_t is SecPkgCredentials_Names*. Same for all mechs (?)
+// gss_cred_id_t is Credentials*. One CredHandle for each mech.
 // gss_ctx_id_t is Context*
 
 typedef struct {
@@ -81,8 +82,20 @@
     struct _SecHandle hCtxt;
     DWORD cbMaxMessage;
     SecPkgContext_Sizes SecPkgContextSizes;
+    SecPkgContext_NativeNames nnames;
+    BOOLEAN established;
 } Context;
 
+typedef struct {
+    TCHAR PackageName[20];
+    CredHandle* phCred;
+} OneCred;
+
+typedef struct {
+    int count;
+    OneCred* creds;
+} Credential;
+
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
@@ -97,7 +110,7 @@
     GetSystemTimeAsFileTime(&fnow);
     a = (ULARGE_INTEGER*)time;
     b = (ULARGE_INTEGER*)&fnow;
-    PP("Difference %ld\n", (long)((a->QuadPart - b->QuadPart) / 10000000));
+    PP("Difference %ld", (long)((a->QuadPart - b->QuadPart) / 10000000));
     return (long)((a->QuadPart - b->QuadPart) / 10000000);
 }
 
@@ -121,7 +134,7 @@
     }
     out->phCred = NULL;
     out->cbMaxMessage = pkgInfo->cbMaxToken;
-    PP("   QuerySecurityPackageInfo %ls goes %ld\n", PackageName, out->cbMaxMessage);
+    PP("   QuerySecurityPackageInfo %ls goes %ld", PackageName, out->cbMaxMessage);
     wcscpy(out->PackageName, PackageName);
     FreeContextBuffer(pkgInfo);
     return out;
@@ -153,6 +166,43 @@
 	return fout;
 }
 
+BOOLEAN
+isKerberosOID(gss_OID mech) {
+    return mech->length == sizeof(KRB5_OID)
+            && !memcmp(mech->elements, KRB5_OID, sizeof(KRB5_OID));
+}
+
+BOOLEAN
+isNegotiateOID(gss_OID mech) {
+    return mech->length == sizeof(SPNEGO_OID)
+            && !memcmp(mech->elements, SPNEGO_OID, sizeof(SPNEGO_OID));
+}
+
+void
+displayOID(gss_OID mech)
+{
+    if (isKerberosOID(mech)) {
+        PP("Kerberos OID");
+    } else if (isNegotiateOID(mech)) {
+        PP("SPNEGO OID");
+    } else {
+        PP("UNKNOWN %d", mech->length);
+    }
+}
+
+void
+displayOidSet(gss_OID_set mechs)
+{
+    if (mechs == NULL) {
+        PP("OID set is NULL");
+        return;
+    }
+    PP("set.count is %d", (int)mechs->count);
+    for (int i = 0; i < mechs->count; i++) {
+        displayOID(&mechs->elements[i]);
+    }
+}
+
 /* End support section */
 
 /* This section holds exported functions that currently have no implementation */
@@ -161,13 +211,14 @@
 gss_release_name(OM_uint32 *minor_status,
                  gss_name_t *name)
 {
-    if (name != NULL) {
-        SecPkgCredentials_Names* names = (SecPkgCredentials_Names*)name;
-        if (names->sUserName != NULL) {
-            delete[] names->sUserName;
-        }
-        delete names;
-        *name = GSS_C_NO_NAME;
+    PP(">>>> Calling gss_release_name...");
+    if (name != NULL && *name != GSS_C_NO_NAME) {
+//        SecPkgCredentials_Names* names = (SecPkgCredentials_Names*)*name;
+//        if (names->sUserName != NULL) {
+//            delete[] names->sUserName;
+//        }
+//        delete names;
+//        *name = GSS_C_NO_NAME;
     }
     return GSS_S_COMPLETE;
 }
@@ -178,13 +229,14 @@
                 gss_OID input_name_type,
                 gss_name_t *output_name)
 {
+    PP(">>>> Calling gss_import_name...");
     if (input_name_buffer == NULL || input_name_buffer->value == NULL
             || input_name_buffer->length == 0) {
-        return GSS_S_BAD_NAME;
+        return GSS_S_CALL_INACCESSIBLE_READ;
     }
     SecPkgCredentials_Names* names = new SecPkgCredentials_Names();
     if (names == NULL) {
-        goto err;
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
     }
     int len = (int)input_name_buffer->length;
     names->sUserName = new SEC_WCHAR[len + 1];
@@ -223,9 +275,10 @@
                  gss_name_t name2,
                  int *name_equal)
 {
+    PP(">>>> Calling gss_compare_name...");
     if (name1 == NULL || name2 == NULL) {
         *name_equal = 0;
-        return GSS_S_BAD_NAME;
+        return GSS_S_CALL_INACCESSIBLE_READ;
     }
 
     SecPkgCredentials_Names* names1 = (SecPkgCredentials_Names*)name1;
@@ -244,6 +297,7 @@
                       gss_OID mech_type,
                       gss_name_t *output_name)
 {
+    PP(">>>> Calling gss_canonicalize_name...");
     SecPkgCredentials_Names* names1 = (SecPkgCredentials_Names*)input_name;
     SecPkgCredentials_Names* names2 = new SecPkgCredentials_Names();
     names2->sUserName = new SEC_WCHAR[lstrlen(names1->sUserName) + 1];
@@ -257,6 +311,7 @@
                 gss_name_t input_name,
                 gss_buffer_t exported_name)
 {
+    PP(">>>> Calling gss_export_name...");
     SecPkgCredentials_Names* names = (SecPkgCredentials_Names*)input_name;
     int len = (int)wcslen(names->sUserName);
     char* buffer = new char[len+1];
@@ -273,6 +328,7 @@
                  gss_buffer_t output_name_buffer,
                  gss_OID *output_name_type)
 {
+    PP(">>>> Calling gss_display_name...");
     SecPkgCredentials_Names* names = (SecPkgCredentials_Names*)input_name;
     int len = (int)wcslen(names->sUserName);
     char* buffer = new char[len+1];
@@ -280,7 +336,7 @@
     buffer[len] = 0;
     output_name_buffer->length = len+1;
     output_name_buffer->value = buffer;
-    PP("Name found: %ls\n", names->sUserName);
+    PP("Name found: %ls", names->sUserName);
     PP("%d [%s]", len, buffer);
     if (output_name_type != NULL) {
         gss_OID_desc* oid = new gss_OID_desc();
@@ -301,32 +357,54 @@
                  gss_OID_set *actual_mechs,
                  OM_uint32 *time_rec)
 {
-    if (desired_name != NULL) {
-        return GSS_S_FAILURE; // Only support default cred
-    }
+    PP(">>>> Calling gss_acquire_cred...");
     SECURITY_STATUS ss;
-    CredHandle* cred = new CredHandle();
     TimeStamp ts;
 	cred_usage = 0;
-    PP("AcquireCredentialsHandle with %d\n", cred_usage);
-    ss = AcquireCredentialsHandle(
-            NULL,
-            L"Kerberos",
-            cred_usage == 0 ? SECPKG_CRED_BOTH :
-                (cred_usage == 1 ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND),
-            NULL,
-            NULL,
-            NULL,
-            NULL,
-            cred,
-            &ts);
-
-    actual_mechs = &desired_mech;
+    PP("AcquireCredentialsHandle with %d %p", cred_usage, desired_mech);
+    displayOidSet(desired_mech);
+    Credential* cred = new Credential();
+    cred->count = (int)desired_mech->count;
+    cred->creds = new OneCred[cred->count];
+    for (int i = 0; i < cred->count; i++) {
+PP("");
+        TCHAR* name = isKerberosOID(&desired_mech->elements[i])
+                ? L"Kerberos" : L"Negotiate";
+PP("");
+        wcscpy(cred->creds[i].PackageName, name);
+        cred->creds[i].phCred = new CredHandle();
+PP("");
+        ss = AcquireCredentialsHandle(
+                NULL,
+                name,
+                cred_usage == 0 ? SECPKG_CRED_BOTH :
+                    (cred_usage == 1 ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND),
+                NULL,
+                NULL,
+                NULL,
+                NULL,
+                cred->creds[i].phCred,
+                &ts);
+PP("");
+    }
+PP("");
+    actual_mechs = &desired_mech; // dup?
     *output_cred_handle = (void*)cred;
     if (time_rec != NULL) {
         *time_rec = TimeStampToLong(&ts);
     }
 
+    if (desired_name != NULL) {
+        gss_name_t realname;
+        gss_inquire_cred(minor_status, *output_cred_handle, &realname,
+                NULL, NULL, NULL);
+        SecPkgCredentials_Names* dnames = (SecPkgCredentials_Names*)desired_name;
+        SecPkgCredentials_Names* rnames = (SecPkgCredentials_Names*)realname;
+        int cmp = lstrcmp(dnames->sUserName, rnames->sUserName);
+        gss_release_name(minor_status, &realname);
+        return cmp ? GSS_S_FAILURE : GSS_S_COMPLETE; // Only support default cred
+    }
+
     return GSS_S_COMPLETE;
 }
 
@@ -334,8 +412,14 @@
 gss_release_cred(OM_uint32 *minor_status,
                  gss_cred_id_t *cred_handle)
 {
+    PP(">>>> Calling gss_release_cred...");
     if (cred_handle && *cred_handle) {
-        FreeCredentialsHandle((CredHandle*)*cred_handle);
+        Credential* cred = (Credential*)*cred_handle;
+        for (int i = 0; i < cred->count; i++) {
+            FreeCredentialsHandle(cred->creds[i].phCred);
+            delete cred->creds[i].phCred;
+        }
+        delete cred;
         *cred_handle = GSS_C_NO_CREDENTIAL;
     }
     return GSS_S_COMPLETE;
@@ -349,7 +433,8 @@
                  gss_cred_usage_t *cred_usage,
                  gss_OID_set *mechanisms)
 {
-    CredHandle* cred = (CredHandle*)cred_handle;
+    PP(">>>> Calling gss_inquire_cred...");
+    CredHandle* cred = ((Credential*)cred_handle)->creds[0].phCred;
     SECURITY_STATUS ss;
     if (name) {
         SecPkgCredentials_Names* names = new SecPkgCredentials_Names();
@@ -365,6 +450,7 @@
                        gss_buffer_t interprocess_token,
                        gss_ctx_id_t *context_handle)
 {
+    PP(">>>> Calling UNIMPLEMENTED gss_import_sec_context...");
     return GSS_S_FAILURE;
 }
 
@@ -383,6 +469,7 @@
                      OM_uint32 *ret_flags,
                      OM_uint32 *time_rec)
 {
+    PP(">>>> Calling gss_init_sec_context...");
     SECURITY_STATUS ss;
     TimeStamp Lifetime;
     SecBufferDesc InBuffDesc;
@@ -392,8 +479,16 @@
 
     Context* pc;
     if (input_token->length == 0) {
-        pc = NewContext(L"Kerberos");
-        pc->phCred = (CredHandle*)initiator_cred_handle;
+        TCHAR* name = isKerberosOID(mech_type) ? L"Kerberos" : L"Negotiate";
+        pc = NewContext(name);
+        Credential* cred = (Credential*)initiator_cred_handle;
+        if (cred != NULL) {
+            for (int i = 0; i < cred->count; i++) {
+                if (!lstrcmp(cred->creds[i].PackageName, name)) {
+                    pc->phCred = cred->creds[i].phCred;
+                }
+            }
+        }
         *context_handle = (gss_ctx_id_t) pc;
     } else {
         pc = (Context*)*context_handle;
@@ -433,7 +528,9 @@
         InSecBuff.pvBuffer = input_token->value;
     } else {
         if (!pc->phCred) {
-            PP("No credentials provided, acquire automatically");
+            PP("No credentials %p provided, acquire %ls automatically",
+                    pc->phCred, pc->PackageName);
+            CredHandle* newCred = new CredHandle();
             ss = AcquireCredentialsHandle(
                     NULL,
                     pc->PackageName,
@@ -442,8 +539,9 @@
                     NULL,
                     NULL,
                     NULL,
-                    pc->phCred,
+                    newCred,
                     &Lifetime);
+            pc->phCred = newCred;
             PP("end");
             if (!(SEC_SUCCESS(ss))) {
                 PP("Failed");
@@ -492,6 +590,8 @@
     if (ss == SEC_I_CONTINUE_NEEDED) {
         return GSS_S_CONTINUE_NEEDED;
     } else {
+        pc->established = true;
+        QueryContextAttributes(&pc->hCtxt, SECPKG_ATTR_NATIVE_NAMES, &pc->nnames);
         *ret_flags |= GSS_C_PROT_READY_FLAG;
         return GSS_S_COMPLETE;
     }
@@ -510,6 +610,7 @@
                        OM_uint32 *time_rec,
                        gss_cred_id_t *delegated_cred_handle)
 {
+    PP(">>>> Calling UNIMPLEMENTED gss_accept_sec_context...");
     return GSS_S_FAILURE;
 }
 
@@ -524,8 +625,25 @@
                     int *locally_initiated,
                     int *open)
 {
+    PP(">>>> Calling UNIMPLEMENTED gss_inquire_context...");
     Context* pc = (Context*) context_handle;
-    return GSS_S_FAILURE;
+    if (!pc->established) {
+        return GSS_S_NO_CONTEXT;
+    }
+    if (src_name != NULL) {
+        SecPkgCredentials_Names* n = new SecPkgCredentials_Names();
+        n->sUserName = new SEC_WCHAR[lstrlen(pc->nnames.sClientName) + 1];
+        lstrcpy(n->sUserName, pc->nnames.sClientName);
+        *src_name = (gss_name_t) n;
+    }
+    if (targ_name != NULL) {
+        SecPkgCredentials_Names* n = new SecPkgCredentials_Names();
+        n->sUserName = new SEC_WCHAR[lstrlen(pc->nnames.sServerName) + 1];
+        lstrcpy(n->sUserName, pc->nnames.sServerName);
+        *targ_name = (gss_name_t) n;
+    }
+    // TODO: other inquiries
+    return GSS_S_COMPLETE;
 }
 
 __declspec(dllexport) OM_uint32
@@ -533,6 +651,7 @@
                        gss_ctx_id_t *context_handle,
                        gss_buffer_t output_token)
 {
+    PP(">>>> Calling UNIMPLEMENTED gss_delete_sec_context...");
     return GSS_S_FAILURE;
 }
 
@@ -541,6 +660,7 @@
                  gss_ctx_id_t context_handle,
                  OM_uint32 *time_rec)
 {
+    PP(">>>> Calling UNIMPLEMENTED gss_context_time...");
     Context* pc = (Context*) context_handle;
     return GSS_S_FAILURE;
 }
@@ -553,6 +673,7 @@
                     OM_uint32 req_output_size,
                     OM_uint32 *max_input_size)
 {
+    PP(">>>> Calling gss_wrap_size_limit...");
     Context* pc = (Context*) context_handle;
     *max_input_size = pc->cbMaxMessage;
     return GSS_S_COMPLETE;
@@ -563,6 +684,7 @@
                        gss_ctx_id_t *context_handle,
                        gss_buffer_t interprocess_token)
 {
+    PP(">>>> Calling UNIMPLEMENTED gss_export_sec_context...");
     return GSS_S_FAILURE;
 }
 
@@ -573,6 +695,7 @@
             gss_buffer_t message_buffer,
             gss_buffer_t msg_token)
 {
+    PP(">>>> Calling gss_get_mic...");
     Context* pc = (Context*) context_handle;
 
     SECURITY_STATUS ss;
@@ -609,6 +732,7 @@
                gss_buffer_t token_buffer,
                gss_qop_t *qop_state)
 {
+    PP(">>>> Calling gss_verify_mic...");
     Context* pc = (Context*) context_handle;
 
     SECURITY_STATUS ss;
@@ -649,6 +773,7 @@
          int *conf_state,
          gss_buffer_t output_message_buffer)
 {
+    PP(">>>> Calling gss_wrap...");
     Context* pc = (Context*) context_handle;
 
     SECURITY_STATUS ss;
@@ -708,6 +833,7 @@
            int *conf_state,
            gss_qop_t *qop_state)
 {
+    PP(">>>> Calling gss_unwrap...");
     Context* pc = (Context*) context_handle;
 
     SECURITY_STATUS ss;
@@ -745,6 +871,7 @@
 gss_indicate_mechs(OM_uint32 *minor_status,
                    gss_OID_set *mech_set)
 {
+    PP(">>>> Calling gss_indicate_mechs...");
     gss_OID_set_desc *copy;
     OM_uint32 minor = 0;
     OM_uint32 major = GSS_S_COMPLETE;
@@ -755,13 +882,13 @@
     ULONG ccPackages;
     PSecPkgInfo packages;
     EnumerateSecurityPackages(&ccPackages, &packages);
-    PP("EnumerateSecurityPackages returns %ld\n", ccPackages);
-    // TODO: only return Kerberos, so no need to check input later
+    PP("EnumerateSecurityPackages returns %ld", ccPackages);
+
     PSecPkgInfo pkgInfo;
     SECURITY_STATUS ss = QuerySecurityPackageInfo(L"Negotiate", &pkgInfo);
     if (ss == SEC_E_OK) {
-        // n++;
-        // hasSpnego = true;
+        n++;
+        hasSpnego = true;
     }
     ss = QuerySecurityPackageInfo(L"Kerberos", &pkgInfo);
     if (ss == SEC_E_OK) {
@@ -791,13 +918,12 @@
     }    
     if (hasSpnego) {
         gss_OID_desc *out = &copy->elements[i];
-        char in[6] = { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x02 };
-        if ((out->elements = new char[sizeof(in)]) == NULL) {
+        if ((out->elements = new char[sizeof(SPNEGO_OID)]) == NULL) {
             major = GSS_S_FAILURE;
             goto done;
         }
-        (void) memcpy(out->elements, in, sizeof(in));
-        out->length = sizeof(in);
+        (void) memcpy(out->elements, SPNEGO_OID, sizeof(SPNEGO_OID));
+        out->length = sizeof(SPNEGO_OID);
         i++;
     }    
     copy->count = i;
@@ -816,6 +942,7 @@
                            const gss_OID mechanism,
                            gss_OID_set *name_types)
 {
+    PP(">>>> Calling UNIMPLEMENTED gss_inquire_names_for_mech...");
     return GSS_S_FAILURE;
 }
 
@@ -824,7 +951,46 @@
                        gss_OID member_oid,
                        gss_OID_set *oid_set)
 {
-    return GSS_S_FAILURE;
+    PP(">>>> Calling gss_add_oid_set_member...");
+    if (member_oid == NULL || member_oid->length == 0
+            || member_oid->elements == NULL) {
+        return GSS_S_CALL_INACCESSIBLE_READ;
+    }
+
+    if (oid_set == NULL) {
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+    }
+
+    int count = (int)(*oid_set)->count;
+    for (int i = 0; i < count; i++) {
+        if ((*oid_set)->elements[i].length == member_oid->length
+                && !memcmp((*oid_set)->elements[i].elements, member_oid->elements, member_oid->length)) {
+            // already there
+            return GSS_S_COMPLETE;
+        }
+    }
+    gss_OID existing = (*oid_set)->elements;
+    gss_OID newcopy = new gss_OID_desc[count + 1];
+    if (newcopy == NULL) {
+        return GSS_S_FAILURE;
+    }
+    if (existing) {
+        memcpy(newcopy, existing, count * sizeof(gss_OID_desc));
+    }
+    newcopy[count].length = member_oid->length;
+    newcopy[count].elements = new char[member_oid->length];
+    if (newcopy[count].elements == NULL) {
+        delete[] newcopy;
+        return GSS_S_FAILURE;
+    }
+    memcpy(newcopy[count].elements, member_oid->elements, member_oid->length);
+    (*oid_set)->elements = newcopy;
+    (*oid_set)->count++;
+    if (existing) {
+        delete[] existing;
+    }
+
+    return GSS_S_COMPLETE;
 }
 
 __declspec(dllexport) OM_uint32
@@ -835,13 +1001,26 @@
                    OM_uint32 *message_context,
                    gss_buffer_t status_string)
 {
-    return GSS_S_FAILURE;
+    PP(">>>> Calling UNIMPLEMENTED gss_display_status...");
+    status_string->value = new char[8];
+    memcpy(status_string->value, "Nothing", 8);
+    status_string->length = 7;
+    return GSS_S_COMPLETE;
 }
 
 __declspec(dllexport) OM_uint32
 gss_create_empty_oid_set(OM_uint32 *minor_status,
                          gss_OID_set *oid_set)
 {
+    PP(">>>> Calling gss_create_empty_oid_set...");
+    if (oid_set == NULL) {
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+    }
+
+    if (*oid_set = new gss_OID_set_desc) {
+        memset(*oid_set, 0, sizeof(gss_OID_set_desc));
+        return GSS_S_COMPLETE;
+    }
     return GSS_S_FAILURE;
 }
 
@@ -849,14 +1028,33 @@
 gss_release_oid_set(OM_uint32 *minor_status,
                     gss_OID_set *set)
 {
-    return GSS_S_FAILURE;
+    PP(">>>> Calling gss_release_oid_set...");
+    if (set == NULL || *set == GSS_C_NO_OID_SET) {
+        return GSS_S_COMPLETE;
+    }
+    for (int i = 0; i < (*set)->count; i++) {
+        delete[] (*set)->elements[i].elements;
+    }
+    delete[] (*set)->elements;
+    delete *set;
+    *set = GSS_C_NO_OID_SET;
+    return GSS_S_COMPLETE;
 }
 
 __declspec(dllexport) OM_uint32
 gss_release_buffer(OM_uint32 *minor_status,
                    gss_buffer_t buffer)
 {
-    return GSS_S_FAILURE;
+    PP(">>>> Calling gss_release_buffer...");
+    if (buffer == NULL) {
+        return GSS_S_COMPLETE;
+    }
+    if (buffer->value) {
+        delete[] buffer->value;
+        buffer->value = NULL;
+        buffer->length = 0;
+    }
+    return GSS_S_COMPLETE;
 }
 
 /* End implemented section */