]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Implement support for unsigned pkinit messages
authorSam Hartman <hartmans@mit.edu>
Wed, 23 Dec 2009 21:09:53 +0000 (21:09 +0000)
committerSam Hartman <hartmans@mit.edu>
Wed, 23 Dec 2009 21:09:53 +0000 (21:09 +0000)
* cms_signeddata_verify will take a ContentInfo as well as SignedData and returns an indication of whether a message is signed
* Accept unsigned authpacks in the  anonymous case.

git-svn-id: svn://anonsvn.mit.edu/krb5/branches/anonymous@23493 dc483132-0cff-0310-8789-dd5450dbe970

src/plugins/preauth/pkinit/pkinit_clnt.c
src/plugins/preauth/pkinit/pkinit_crypto.h
src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
src/plugins/preauth/pkinit/pkinit_srv.c

index ba1e4344fe51bbe5c4f0161980b20979c6224984..46ca022b7e3431111d2e392bbd8e2b448b939c12 100644 (file)
@@ -61,7 +61,8 @@ static krb5_error_code
 pkinit_as_req_create(krb5_context context, pkinit_context plgctx,
                      pkinit_req_context reqctx, krb5_timestamp ctsec,
                      krb5_int32 cusec, krb5_ui_4 nonce,
-                     const krb5_checksum *cksum, krb5_principal server,
+                     const krb5_checksum *cksum,
+                     krb5_principal client, krb5_principal server,
                      krb5_data **as_req);
 
 static krb5_error_code
@@ -139,7 +140,7 @@ pa_pkinit_gen_req(krb5_context context,
     nonce = request->nonce;
 
     retval = pkinit_as_req_create(context, plgctx, reqctx, ctsec, cusec,
-                                  nonce, &cksum, request->server, &out_data);
+                                  nonce, &cksum, request->client, request->server, &out_data);
     if (retval || !out_data->length) {
         pkiDebug("error %d on pkinit_as_req_create; aborting PKINIT\n",
                  (int) retval);
@@ -218,6 +219,7 @@ pkinit_as_req_create(krb5_context context,
                      krb5_int32 cusec,
                      krb5_ui_4 nonce,
                      const krb5_checksum * cksum,
+                     krb5_principal client,
                      krb5_principal server,
                      krb5_data ** as_req)
 {
@@ -344,10 +346,17 @@ pkinit_as_req_create(krb5_context context,
             retval = ENOMEM;
             goto cleanup;
         }
-        retval = cms_signeddata_create(context, plgctx->cryptoctx,
-                                       reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_CLIENT, 1,
-                                       (unsigned char *)coded_auth_pack->data, coded_auth_pack->length,
-                                       &req->signedAuthPack.data, &req->signedAuthPack.length);
+        /*For the new protocol, we support anonymous*/
+        if (krb5_principal_compare_any_realm(context, client,
+                                             krb5_anonymous_principal()))
+            retval = cms_contentinfo_create(context, plgctx->cryptoctx,
+                                            reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_CLIENT,
+                                            (unsigned char *)coded_auth_pack->data, coded_auth_pack->length,
+                                            &req->signedAuthPack.data, &req->signedAuthPack.length);
+            else         retval = cms_signeddata_create(context, plgctx->cryptoctx,
+                                                        reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_CLIENT, 1,
+                                                        (unsigned char *)coded_auth_pack->data, coded_auth_pack->length,
+                                                        &req->signedAuthPack.data, &req->signedAuthPack.length);
 #ifdef DEBUG_ASN1
         print_buffer_bin((unsigned char *)req->signedAuthPack.data,
                          req->signedAuthPack.length,
@@ -677,7 +686,7 @@ pkinit_as_rep_parse(krb5_context context,
                                             reqctx->opts->require_crl_checking,
                                             kdc_reply->u.dh_Info.dhSignedData.data,
                                             kdc_reply->u.dh_Info.dhSignedData.length,
-                                            &dh_data.data, &dh_data.length, NULL, NULL)) != 0) {
+                                            &dh_data.data, &dh_data.length, NULL, NULL, NULL)) != 0) {
             pkiDebug("failed to verify pkcs7 signed data\n");
             goto cleanup;
         }
index 718a238247dadeb9c0ab1fa2b0d21e2d1fbdd1e0..dedd8f9456f17e359597cc81ca2854f7bc03c212 100644 (file)
@@ -181,8 +181,9 @@ krb5_error_code cms_signeddata_verify
                    receives required authorization data that
                    contains the verified certificate chain
                    (only used by the KDC) */
-       unsigned int *authz_data_len);                  /* OUT
-                   receives length of authz_data */
+        unsigned int *authz_data_len,                  /* OUT
+                                                          receives length of authz_data */
+        int *is_signed /*out: is message signed*/);
 
 /*
  * this function creates a CMS message where eContentType is EnvelopedData
index bfb3bf1584f091a3330ce461ca64d8028b365f86..fc1b1bc3860e39e9543f0dea7c9ed3dc9c4d85e0 100644 (file)
@@ -1120,8 +1120,9 @@ cms_signeddata_verify(krb5_context context,
                       unsigned char **data,
                       unsigned int *data_len,
                       unsigned char **authz_data,
-                      unsigned int *authz_data_len)
-{
+                      unsigned int *authz_data_len,
+                      int *is_signed)
+    {
     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
     PKCS7 *p7 = NULL;
     BIO *out = NULL;
@@ -1146,7 +1147,8 @@ cms_signeddata_verify(krb5_context context,
     print_buffer_bin(signed_data, signed_data_len,
                      "/tmp/client_received_pkcs7_signeddata");
 #endif
-
+    if (is_signed)
+        *is_signed = 1;
     /* Do this early enough to create the shadow OID for pkcs7-data if needed */
     oid = pkinit_pkcs7type2oid(plgctx, cms_msg_type);
     if (oid == NULL)
@@ -1162,12 +1164,32 @@ cms_signeddata_verify(krb5_context context,
         goto cleanup;
     }
 
-    /* verify that the received message is PKCS7 SignedData message */
-    if (OBJ_obj2nid(p7->type) != NID_pkcs7_signed) {
-        pkiDebug("Expected id-signedData PKCS7 msg (received type = %d)\n",
-                 OBJ_obj2nid(p7->type));
-        krb5_set_error_message(context, retval, "wrong oid\n");
-        goto cleanup;
+/*Handle the case in pkinit anonymous where  we get unsigned data.*/
+    if (is_signed && !OBJ_cmp( p7->type, oid)) {
+        unsigned char *d;
+        *is_signed = 0;
+        if (p7->d.other->type != V_ASN1_OCTET_STRING) {
+            retval = KRB5KDC_ERR_PREAUTH_FAILED;
+            krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED, "Invalid pkinit packet: octet string expected");
+            goto cleanup;
+        }
+        *data_len = ASN1_STRING_length(p7->d.other->value.octet_string);
+        d = malloc(*data_len);
+        if (d == NULL) {
+            retval = ENOMEM;
+            goto cleanup;
+        }
+        memcpy(d, ASN1_STRING_data(p7->d.other->value.octet_string),
+               *data_len);
+        *data = d;
+        goto out;
+    } else     /* verify that the received message is PKCS7 SignedData message */
+        if (OBJ_obj2nid(p7->type) != NID_pkcs7_signed) {
+
+            pkiDebug("Expected id-signedData PKCS7 msg (received type = %d)\n",
+                     OBJ_obj2nid(p7->type));
+            krb5_set_error_message(context, retval, "wrong oid\n");
+            goto cleanup;
     }
 
     /* setup to verify X509 certificate used to sign PKCS7 message */
@@ -1370,7 +1392,6 @@ cms_signeddata_verify(krb5_context context,
     for (size = 0;;) {
         int remain;
         retval = ENOMEM;
-
         if ((*data = realloc(*data, size + 1024 * 10)) == NULL)
             goto cleanup;
         remain = BIO_read(out, &((*data)[size]), 1024 * 10);
@@ -1703,7 +1724,7 @@ cms_envelopeddata_verify(krb5_context context,
                                    id_cryptoctx, msg_type,
                                    require_crl_checking,
                                    vfy_buf, vfy_buf_len,
-                                   data, data_len, NULL, NULL);
+                                   data, data_len, NULL, NULL, NULL);
 
     if (!retval)
         pkiDebug("PKCS7 Verification Success\n");
index fcd3e78699e45f1c380de482c6339d67e6a46f1a..db9b568aa36345334fe59529af069948b10606d7 100644 (file)
@@ -314,6 +314,7 @@ pkinit_server_verify_padata(krb5_context context,
     krb5_authdata **my_authz_data = NULL, *pkinit_authz_data = NULL;
     krb5_kdc_req *tmp_as_req = NULL;
     krb5_data k5data;
+    int is_signed = 1;
     krb5_keyblock *armor_key;
 
     pkiDebug("pkinit_verify_padata: entered!\n");
@@ -367,7 +368,7 @@ pkinit_server_verify_padata(krb5_context context,
                                        plgctx->opts->require_crl_checking,
                                        reqp->signedAuthPack.data, reqp->signedAuthPack.length,
                                        &authp_data.data, &authp_data.length, &krb5_authz.data,
-                                       &krb5_authz.length);
+                                       &krb5_authz.length, &is_signed);
         break;
     case KRB5_PADATA_PK_AS_REP_OLD:
     case KRB5_PADATA_PK_AS_REQ_OLD:
@@ -389,7 +390,7 @@ pkinit_server_verify_padata(krb5_context context,
                                        plgctx->opts->require_crl_checking,
                                        reqp9->signedAuthPack.data, reqp9->signedAuthPack.length,
                                        &authp_data.data, &authp_data.length, &krb5_authz.data,
-                                       &krb5_authz.length);
+                                       &krb5_authz.length, NULL);
         break;
     default:
         pkiDebug("unrecognized pa_type = %d\n", data->pa_type);
@@ -400,28 +401,35 @@ pkinit_server_verify_padata(krb5_context context,
         pkiDebug("pkcs7_signeddata_verify failed\n");
         goto cleanup;
     }
+    if (is_signed) {
 
-    retval = verify_client_san(context, plgctx, reqctx, request->client,
-                               &valid_san);
-    if (retval)
-        goto cleanup;
-    if (!valid_san) {
-        pkiDebug("%s: did not find an acceptable SAN in user certificate\n",
-                 __FUNCTION__);
-        retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
-        goto cleanup;
-    }
-    retval = verify_client_eku(context, plgctx, reqctx, &valid_eku);
-    if (retval)
-        goto cleanup;
+        retval = verify_client_san(context, plgctx, reqctx, request->client,
+                                   &valid_san);
+        if (retval)
+            goto cleanup;
+        if (!valid_san) {
+            pkiDebug("%s: did not find an acceptable SAN in user certificate\n",
+                     __FUNCTION__);
+            retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
+            goto cleanup;
+        }
+        retval = verify_client_eku(context, plgctx, reqctx, &valid_eku);
+        if (retval)
+            goto cleanup;
 
-    if (!valid_eku) {
-        pkiDebug("%s: did not find an acceptable EKU in user certificate\n",
-                 __FUNCTION__);
-        retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
-        goto cleanup;
+        if (!valid_eku) {
+            pkiDebug("%s: did not find an acceptable EKU in user certificate\n",
+                     __FUNCTION__);
+            retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
+            goto cleanup;
+        }
+    } else { /*!is_signed*/
+        if (!krb5_principal_compare( context, request->client, krb5_anonymous_principal())) {
+            retval = KRB5KDC_ERR_PREAUTH_FAILED;
+            krb5_set_error_message(context, retval, "Pkinit request not signed, but client not anonymous.");
+            goto cleanup;
+        }
     }
-
 #ifdef DEBUG_ASN1
     print_buffer_bin(authp_data.data, authp_data.length, "/tmp/kdc_auth_pack");
 #endif
@@ -446,6 +454,11 @@ pkinit_server_verify_padata(krb5_context context,
                 pkiDebug("bad dh parameters\n");
                 goto cleanup;
             }
+        } else if (!is_signed) {
+            /*Anonymous pkinit requires DH*/
+            retval = KRB5KDC_ERR_PREAUTH_FAILED;
+            krb5_set_error_message(context, retval, "Anonymous pkinit without DH public value not supported.");
+            goto cleanup;
         }
         /*
          * The KDC may have modified the request after decoding it.