Fixes for Heimdal (macOS) builds from Stefan.
[mech_eap.git] / mech_eap / util_krb.c
index 8589aa0..f629a32 100644 (file)
@@ -68,12 +68,15 @@ initKrbContext(krb5_context *pKrbContext)
     *pKrbContext = krbContext;
 
 cleanup:
+#ifdef HAVE_HEIMDAL_VERSION
+    krb5_xfree(defaultRealm);
+#else
+    krb5_free_default_realm(krbContext, defaultRealm);
+#endif
+
     if (code != 0 && krbContext != NULL)
         krb5_free_context(krbContext);
 
-    if (defaultRealm != NULL)
-        GSSEAP_FREE(defaultRealm);
-
     return code;
 }
 
@@ -83,18 +86,23 @@ gssEapKerberosInit(OM_uint32 *minor, krb5_context *context)
     struct gss_eap_thread_local_data *tld;
 
     *minor = 0;
+    *context = NULL;
 
     tld = gssEapGetThreadLocalData();
     if (tld != NULL) {
-        *context = tld->krbContext;
-        if (*context == NULL) {
-            *minor = initKrbContext(context);
-            if (*minor == 0)
-                tld->krbContext = *context;
+        if (tld->krbContext == NULL) {
+            *minor = initKrbContext(&tld->krbContext);
+            if (*minor != 0)
+                tld->krbContext = NULL;
         }
+        *context = tld->krbContext;
+    } else {
+        *minor = GSSEAP_GET_LAST_ERROR();
     }
 
-    return *minor == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
+    GSSEAP_ASSERT(*context != NULL || *minor != 0);
+
+    return (*minor == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
 }
 
 /*
@@ -105,6 +113,9 @@ gssEapKerberosInit(OM_uint32 *minor, krb5_context *context)
  * Tn = pseudo-random(KMSK, n || "rfc4121-gss-eap")
  * L = output key size
  * K = truncate(L, T1 || T2 || .. || Tn)
+ *
+ * The output must be freed by krb5_free_keyblock_contents(),
+ * not GSSEAP_FREE().
  */
 OM_uint32
 gssEapDeriveRfc3961Key(OM_uint32 *minor,
@@ -114,44 +125,48 @@ gssEapDeriveRfc3961Key(OM_uint32 *minor,
                        krb5_keyblock *pKey)
 {
     krb5_context krbContext;
-#ifndef HAVE_HEIMDAL_VERSION
+#ifdef HAVE_HEIMDAL_VERSION
+    krb5_crypto krbCrypto = NULL;
+#else
     krb5_data data;
 #endif
-    krb5_data ns, t, prfOut;
+    krb5_data ns, t, derivedKeyData;
     krb5_keyblock kd;
     krb5_error_code code;
     size_t randomLength, keyLength, prfLength;
     unsigned char constant[4 + sizeof("rfc4121-gss-eap") - 1], *p;
     ssize_t i, remain;
 
-    assert(encryptionType != ENCTYPE_NULL);
-
-    memset(pKey, 0, sizeof(*pKey));
-
     GSSEAP_KRB_INIT(&krbContext);
+    GSSEAP_ASSERT(encryptionType != ENCTYPE_NULL);
 
+    KRB_KEY_INIT(pKey);
     KRB_KEY_INIT(&kd);
     KRB_KEY_TYPE(&kd) = encryptionType;
 
-    t.data = NULL;
-    t.length = 0;
+    KRB_DATA_INIT(&ns);
+    KRB_DATA_INIT(&t);
+    KRB_DATA_INIT(&derivedKeyData);
+
+#ifdef HAVE_HEIMDAL_VERSION
+    code = krb5_enctype_keybits(krbContext, encryptionType, &randomLength);
+    if (code != 0)
+        goto cleanup;
 
-    prfOut.data = NULL;
-    prfOut.length = 0;
+    randomLength = (randomLength + 7) / 8; /* from mit_glue.c */
 
+    code = krb5_enctype_keysize(krbContext, encryptionType, &keyLength);
+    if (code != 0)
+        goto cleanup;
+#else
     code = krb5_c_keylengths(krbContext, encryptionType,
                              &randomLength, &keyLength);
     if (code != 0)
         goto cleanup;
+#endif /* HAVE_HEIMDAL_VERSION */
 
-    KRB_KEY_DATA(&kd) = GSSEAP_MALLOC(keyLength);
-    if (KRB_KEY_DATA(&kd) == NULL) {
-        code = ENOMEM;
-        goto cleanup;
-    }
-    KRB_KEY_LENGTH(&kd) = keyLength;
+    /* Convert EAP MSK into a Kerberos key */
 
-    /* Convert MSK into a Kerberos key */
 #ifdef HAVE_HEIMDAL_VERSION
     code = krb5_random_to_key(krbContext, encryptionType, inputKey,
                               MIN(inputKeyLength, randomLength), &kd);
@@ -159,8 +174,15 @@ gssEapDeriveRfc3961Key(OM_uint32 *minor,
     data.length = MIN(inputKeyLength, randomLength);
     data.data = (char *)inputKey;
 
+    KRB_KEY_DATA(&kd) = KRB_MALLOC(keyLength);
+    if (KRB_KEY_DATA(&kd) == NULL) {
+        code = ENOMEM;
+        goto cleanup;
+    }
+    KRB_KEY_LENGTH(&kd) = keyLength;
+
     code = krb5_c_random_to_key(krbContext, encryptionType, &data, &kd);
-#endif
+#endif /* HAVE_HEIMDAL_VERSION */
     if (code != 0)
         goto cleanup;
 
@@ -171,31 +193,45 @@ gssEapDeriveRfc3961Key(OM_uint32 *minor,
     ns.data = (char *)constant;
 
     /* Plug derivation constant and key into PRF */
+#ifdef HAVE_HEIMDAL_VERSION
+    code = krb5_crypto_prf_length(krbContext, encryptionType, &prfLength);
+#else
     code = krb5_c_prf_length(krbContext, encryptionType, &prfLength);
+#endif
     if (code != 0)
         goto cleanup;
 
+#ifdef HAVE_HEIMDAL_VERSION
+    code = krb5_crypto_init(krbContext, &kd, 0, &krbCrypto);
+    if (code != 0)
+        goto cleanup;
+#else
     t.length = prfLength;
     t.data = GSSEAP_MALLOC(t.length);
     if (t.data == NULL) {
         code = ENOMEM;
         goto cleanup;
     }
+#endif
 
-    prfOut.length = randomLength;
-    prfOut.data = GSSEAP_MALLOC(prfOut.length);
-    if (prfOut.data == NULL) {
+    derivedKeyData.length = randomLength;
+    derivedKeyData.data = GSSEAP_MALLOC(derivedKeyData.length);
+    if (derivedKeyData.data == NULL) {
         code = ENOMEM;
         goto cleanup;
     }
 
-    for (i = 0, p = (unsigned char *)prfOut.data, remain = randomLength;
+    for (i = 0, p = (unsigned char *)derivedKeyData.data, remain = randomLength;
          remain > 0;
          p += t.length, remain -= t.length, i++)
     {
         store_uint32_be(i, ns.data);
 
+#ifdef HAVE_HEIMDAL_VERSION
+        code = krb5_crypto_prf(krbContext, krbCrypto, &ns, &t);
+#else
         code = krb5_c_prf(krbContext, &kd, &ns, &t);
+#endif
         if (code != 0)
             goto cleanup;
 
@@ -204,31 +240,39 @@ gssEapDeriveRfc3961Key(OM_uint32 *minor,
 
     /* Finally, convert PRF output into a new key which we will return */
 #ifdef HAVE_HEIMDAL_VERSION
+    krb5_free_keyblock_contents(krbContext, &kd);
+    KRB_KEY_INIT(&kd);
+
     code = krb5_random_to_key(krbContext, encryptionType,
-                              prfOut.data, prfOut.length, &kd);
+                              derivedKeyData.data, derivedKeyData.length, &kd);
 #else
-    code = krb5_c_random_to_key(krbContext, encryptionType, &prfOut, &kd);
+    code = krb5_c_random_to_key(krbContext, encryptionType,
+                                &derivedKeyData, &kd);
 #endif
     if (code != 0)
         goto cleanup;
 
     *pKey = kd;
-    KRB_KEY_DATA(&kd) = NULL;
 
 cleanup:
-    if (KRB_KEY_DATA(&kd) != NULL) {
-        memset(KRB_KEY_DATA(&kd), 0, KRB_KEY_LENGTH(&kd));
-        GSSEAP_FREE(KRB_KEY_DATA(&kd));
-    }
+    if (code != 0)
+        krb5_free_keyblock_contents(krbContext, &kd);
+#ifdef HAVE_HEIMDAL_VERSION
+    krb5_crypto_destroy(krbContext, krbCrypto);
+    krb5_data_free(&t);
+#else
     if (t.data != NULL) {
         memset(t.data, 0, t.length);
         GSSEAP_FREE(t.data);
     }
-    if (prfOut.data != NULL) {
-        memset(prfOut.data, 0, prfOut.length);
-        GSSEAP_FREE(prfOut.data);
+#endif
+    if (derivedKeyData.data != NULL) {
+        memset(derivedKeyData.data, 0, derivedKeyData.length);
+        GSSEAP_FREE(derivedKeyData.data);
     }
+
     *minor = code;
+
     return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
 }
 
@@ -243,10 +287,13 @@ rfc3961ChecksumTypeForKey(OM_uint32 *minor,
                           krb5_cksumtype *cksumtype)
 {
     krb5_context krbContext;
-#ifndef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
+#if !defined(HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE) && !defined(HAVE_HEIMDAL_VERSION)
     krb5_data data;
     krb5_checksum cksum;
 #endif
+#ifdef HAVE_HEIMDAL_VERSION
+    krb5_crypto krbCrypto = NULL;
+#endif
 
     GSSEAP_KRB_INIT(&krbContext);
 
@@ -255,9 +302,19 @@ rfc3961ChecksumTypeForKey(OM_uint32 *minor,
                                            cksumtype);
     if (*minor != 0)
         return GSS_S_FAILURE;
+#elif defined(HAVE_HEIMDAL_VERSION)
+    *minor = krb5_crypto_init(krbContext, key, 0, &krbCrypto);
+    if (*minor != 0)
+        return GSS_S_FAILURE;
+
+    *minor = krb5_crypto_get_checksum_type(krbContext, krbCrypto, cksumtype);
+
+    krb5_crypto_destroy(krbContext, krbCrypto);
+
+    if (*minor != 0)
+        return GSS_S_FAILURE;
 #else
-    data.length = 0;
-    data.data = NULL;
+    KRB_DATA_INIT(&data);
 
     memset(&cksum, 0, sizeof(cksum));
 
@@ -270,16 +327,17 @@ rfc3961ChecksumTypeForKey(OM_uint32 *minor,
     if (*minor != 0)
         return GSS_S_FAILURE;
 
-#ifdef HAVE_HEIMDAL_VERSION
-    *cksumtype = cksum.cksumtype;
-#else
-    *cksumtype = cksum.checksum_type;
-#endif
+    *cksumtype = KRB_CHECKSUM_TYPE(&cksum);
 
-    krb5_free_checksum_contents(krbContext, &cksum);
+    KRB_CHECKSUM_FREE(krbContext, &cksum);
 #endif /* HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE */
 
-    if (!krb5_c_is_keyed_cksum(*cksumtype)) {
+#ifdef HAVE_HEIMDAL_VERSION
+    if (!krb5_checksum_is_keyed(krbContext, *cksumtype))
+#else
+    if (!krb5_c_is_keyed_cksum(*cksumtype))
+#endif
+    {
         *minor = (OM_uint32)KRB5KRB_AP_ERR_INAPP_CKSUM;
         return GSS_S_FAILURE;
     }
@@ -292,7 +350,7 @@ krbCryptoLength(krb5_context krbContext,
 #ifdef HAVE_HEIMDAL_VERSION
                 krb5_crypto krbCrypto,
 #else
-                krb5_keyblock *key,
+                const krb5_keyblock *key,
 #endif
                 int type,
                 size_t *length)
@@ -316,7 +374,7 @@ krbPaddingLength(krb5_context krbContext,
 #ifdef HAVE_HEIMDAL_VERSION
                  krb5_crypto krbCrypto,
 #else
-                 krb5_keyblock *key,
+                 const krb5_keyblock *key,
 #endif
                  size_t dataLength,
                  size_t *padLength)
@@ -359,7 +417,7 @@ krbBlockSize(krb5_context krbContext,
 #ifdef HAVE_HEIMDAL_VERSION
                  krb5_crypto krbCrypto,
 #else
-                 krb5_keyblock *key,
+                 const krb5_keyblock *key,
 #endif
                  size_t *blockSize)
 {
@@ -422,6 +480,7 @@ krbEnctypeToString(
     return 0;
 }
 
+#ifdef GSSEAP_ENABLE_REAUTH
 krb5_error_code
 krbMakeAuthDataKdcIssued(krb5_context context,
                          const krb5_keyblock *key,
@@ -463,7 +522,7 @@ krbMakeAuthDataKdcIssued(krb5_context context,
     if (code != 0)
         goto cleanup;
 
-    GSSEAP_FREE(buf);
+    free(buf); /* match ASN1_MALLOC_ENCODE */
     buf = NULL;
 
     ASN1_MALLOC_ENCODE(AD_KDCIssued, buf, buf_size, &kdcIssued, &len, code);
@@ -480,7 +539,7 @@ krbMakeAuthDataKdcIssued(krb5_context context,
 
 cleanup:
     if (buf != NULL)
-        GSSEAP_FREE(buf);
+        free(buf); /* match ASN1_MALLOC_ENCODE */
     if (crypto != NULL)
         krb5_crypto_destroy(context, crypto);
     free_Checksum(&kdcIssued.ad_checksum);
@@ -617,3 +676,4 @@ cleanup:
     return code;
 #endif /* HAVE_HEIMDAL_VERSION */
 }
+#endif /* GSSEAP_ENABLE_REAUTH */