svn rev #25191: trunk/src/plugins/preauth/pkinit/
hartmans@MIT.EDU
hartmans at MIT.EDU
Sun Sep 18 20:34:57 EDT 2011
http://src.mit.edu/fisheye/changelog/krb5/?cs=25191
Commit By: hartmans
Log Message:
implementation of new function and test program for pkinit agility.
Implementation of pkinit_alg_agility_kdf() function to implement the
key derivation function defined in draft-ietf-krb-wg-pkinit-alg-agility-04,
and implementation of pkinit_kdf_test program to test the new KDF
against the test vector in the draft.
Signed-off-by: Margaret Wasserman <mrw at painless-security.com>
Changed Files:
U trunk/src/plugins/preauth/pkinit/Makefile.in
U trunk/src/plugins/preauth/pkinit/pkinit_crypto.h
U trunk/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
A trunk/src/plugins/preauth/pkinit/pkinit_kdf_constants.c
A trunk/src/plugins/preauth/pkinit/pkinit_kdf_test.c
Modified: trunk/src/plugins/preauth/pkinit/Makefile.in
===================================================================
--- trunk/src/plugins/preauth/pkinit/Makefile.in 2011-09-19 00:34:52 UTC (rev 25190)
+++ trunk/src/plugins/preauth/pkinit/Makefile.in 2011-09-19 00:34:57 UTC (rev 25191)
@@ -8,6 +8,7 @@
DEFS=@DEFS@
LOCALINCLUDES = -I../../../include/krb5 -I.
+RUN_SETUP = @KRB5_RUN_ENV@
LIBBASE=pkinit
LIBMAJOR=0
@@ -29,6 +30,7 @@
pkinit_srv.o \
pkinit_lib.o \
pkinit_clnt.o \
+ pkinit_kdf_constants.o \
pkinit_profile.o \
pkinit_identity.o \
pkinit_matching.o \
@@ -38,6 +40,8 @@
$(srcdir)/pkinit_accessor.c \
$(srcdir)/pkinit_srv.c \
$(srcdir)/pkinit_lib.c \
+ $(srcdir)/pkinit_kdf_test.c \
+ $(srcdir)/pkinit_kdf_constants.c \
$(srcdir)/pkinit_clnt.c \
$(srcdir)/pkinit_profile.c \
$(srcdir)/pkinit_identity.c \
@@ -50,7 +54,14 @@
clean::
$(RM) lib$(LIBBASE)$(SO_EXT)
+ $(RM) pkinit_test_kdf
+check-unix:: pkinit_kdf_test
+ $(RUN_SETUP) $(VALGRIND) ./pkinit_kdf_test
+
+pkinit_kdf_test: pkinit_kdf_test.o $(STLIBOBJS) $(SHLIB_EXPDEPS)
+ $(CC_LINK) -o $@ pkinit_kdf_test.o $(STLIBOBJS) $(SHLIB_EXPLIBS)
+
@libnover_frag@
@libobj_frag@
Modified: trunk/src/plugins/preauth/pkinit/pkinit_crypto.h
===================================================================
--- trunk/src/plugins/preauth/pkinit/pkinit_crypto.h 2011-09-19 00:34:52 UTC (rev 25190)
+++ trunk/src/plugins/preauth/pkinit/pkinit_crypto.h 2011-09-19 00:34:57 UTC (rev 25191)
@@ -631,4 +631,23 @@
krb5_prompter_fct prompter, /* IN */
void *prompter_data); /* IN */
+krb5_error_code
+pkinit_alg_agility_kdf(krb5_context context,
+ krb5_octet_data *secret,
+ krb5_algorithm_identifier *alg_id,
+ krb5_principal party_u_info,
+ krb5_principal party_v_info,
+ krb5_enctype enctype,
+ krb5_octet_data *as_req,
+ krb5_octet_data *pk_as_rep,
+ const krb5_ticket *ticket,
+ krb5_keyblock *key_block);
+
+extern const krb5_octet krb5_pkinit_sha1_oid[];
+extern const size_t krb5_pkinit_sha1_oid_len;
+extern const krb5_octet krb5_pkinit_sha256_oid[];
+extern const size_t krb5_pkinit_sha256_oid_len;
+extern const krb5_octet krb5_pkinit_sha512_oid[];
+extern const size_t krb5_pkinit_sha512_oid_len;
+
#endif /* _PKINIT_CRYPTO_H */
Modified: trunk/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
===================================================================
--- trunk/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c 2011-09-19 00:34:52 UTC (rev 25190)
+++ trunk/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c 2011-09-19 00:34:57 UTC (rev 25191)
@@ -2101,7 +2101,7 @@
krb5_enctype etype,
unsigned char *key,
unsigned int dh_key_len,
- krb5_keyblock * key_block)
+ krb5_keyblock *key_block)
{
krb5_error_code retval;
unsigned char *buf = NULL;
@@ -2140,7 +2140,7 @@
retval = krb5_c_keylengths(context, etype, &keybytes, &keylength);
if (retval)
- goto cleanup;
+ goto cleanup;
key_block->length = keylength;
key_block->contents = malloc(keylength);
@@ -2156,7 +2156,7 @@
cleanup:
free(buf);
- // If this is an error return, free the allocated keyblock, if any
+ /* If this is an error return, free the allocated keyblock, if any */
if (retval) {
krb5_free_keyblock_contents(context, key_block);
}
@@ -2164,6 +2164,208 @@
return retval;
}
+
+/**
+ * Given an algorithm_identifier, this function returns the hash length
+ * and EVP function associated with that algorithm.
+ */
+static krb5_error_code
+pkinit_alg_values(krb5_context context,
+ krb5_algorithm_identifier *alg_id,
+ size_t *hash_bytes,
+ const EVP_MD *(**func)(void))
+{
+ *hash_bytes = 0;
+ *func = NULL;
+ if ((alg_id->algorithm.length == krb5_pkinit_sha1_oid_len) &&
+ (0 == memcmp(alg_id->algorithm.data, &krb5_pkinit_sha1_oid,
+ krb5_pkinit_sha1_oid_len))) {
+ *hash_bytes = 20;
+ *func = &EVP_sha1;
+ return 0;
+ }
+ else if ((alg_id->algorithm.length == krb5_pkinit_sha256_oid_len) &&
+ (0 == memcmp(alg_id->algorithm.data, krb5_pkinit_sha256_oid,
+ krb5_pkinit_sha256_oid_len))) {
+ *hash_bytes = 32;
+ *func = &EVP_sha256;
+ return 0;
+ }
+ else if ((alg_id->algorithm.length == krb5_pkinit_sha512_oid_len) &&
+ (0 == memcmp(alg_id->algorithm.data, krb5_pkinit_sha512_oid,
+ krb5_pkinit_sha512_oid_len))) {
+ *hash_bytes = 32;
+ *func = &EVP_sha512;
+ return 0;
+ }
+ else {
+ krb5_set_error_message(context, KRB5_ERR_BAD_S2K_PARAMS,
+ "Bad algorithm ID passed to PK-INIT KDF.");
+ return KRB5_ERR_BAD_S2K_PARAMS;
+ }
+} /* pkinit_alg_values() */
+
+
+/* pkinit_alg_agility_kdf() --
+ * This function generates a key using the KDF described in
+ * draft_ietf_krb_wg_pkinit_alg_agility-04.txt. The algorithm is
+ * described as follows:
+ *
+ * 1. reps = keydatalen (K) / hash length (H)
+ *
+ * 2. Initialize a 32-bit, big-endian bit string counter as 1.
+ *
+ * 3. For i = 1 to reps by 1, do the following:
+ *
+ * - Compute Hashi = H(counter || Z || OtherInfo).
+ *
+ * - Increment counter (modulo 2^32)
+ *
+ * 4. Set key = Hash1 || Hash2 || ... so that length of key is K bytes.
+ */
+krb5_error_code
+pkinit_alg_agility_kdf(krb5_context context,
+ krb5_octet_data *secret,
+ krb5_algorithm_identifier *alg_id,
+ krb5_principal party_u_info,
+ krb5_principal party_v_info,
+ krb5_enctype enctype,
+ krb5_octet_data *as_req,
+ krb5_octet_data *pk_as_rep,
+ const krb5_ticket *ticket,
+ krb5_keyblock *key_block)
+{
+ krb5_error_code retval = 0;
+
+ unsigned int reps = 0;
+ uint32_t counter = 1; /* Does this type work on Windows? */
+ size_t offset = 0;
+ size_t hash_len = 0;
+ unsigned char *rand_buf = NULL;
+ krb5_data random_data;
+ krb5_sp80056a_other_info other_info_fields;
+ krb5_pkinit_supp_pub_info supp_pub_info_fields;
+ krb5_data *other_info = NULL;
+ krb5_data *supp_pub_info = NULL;
+ const EVP_MD *(*EVP_func)(void);
+
+ /* initialize random_data here to make clean-up safe */
+ random_data.length = 0;
+ random_data.data = NULL;
+
+ /* allocate and initialize the key block */
+ key_block->magic = 0;
+ key_block->enctype = enctype;
+ if (0 != (retval = krb5_c_keylengths(context, enctype, (size_t *)NULL,
+ (size_t *)&(key_block->length))))
+ goto cleanup;
+ if (NULL == (key_block->contents = malloc(key_block->length))) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ memset (key_block->contents, 0, key_block->length);
+
+ if (0 != (retval = pkinit_alg_values(context, alg_id, &hash_len, &EVP_func)))
+ goto cleanup;
+
+ /* 1. reps = keydatalen (K) / hash length (H) */
+ reps = key_block->length/hash_len;
+
+ /* ... and round up, if necessary */
+ if (key_block->length > (reps * hash_len))
+ reps++;
+
+ /* Allocate enough space in the random data buffer to hash directly into
+ * it, even if the last hash will make it bigger than the key length. */
+ if (NULL == (rand_buf = malloc(reps * hash_len))) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ memset(rand_buf, 0, reps * hash_len);
+
+ random_data.length = reps * hash_len;
+ random_data.data = (char *)rand_buf;
+
+ /* Encode the ASN.1 octet string for "SuppPubInfo" */
+ supp_pub_info_fields.enctype = enctype;
+ supp_pub_info_fields.as_req = *as_req;
+ supp_pub_info_fields.pk_as_rep = *pk_as_rep;
+ supp_pub_info_fields.ticket = (krb5_ticket *) ticket;
+ if (0 != ((retval = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields,
+ &supp_pub_info))))
+ goto cleanup;
+
+ /* Now encode the ASN.1 octet string for "OtherInfo" */
+ other_info_fields.algorithm_identifier = *alg_id;
+ other_info_fields.party_u_info = party_u_info;
+ other_info_fields.party_v_info = party_v_info;
+ other_info_fields.supp_pub_info = *supp_pub_info;
+ if (0 != (retval = encode_krb5_sp80056a_other_info(&other_info_fields, &other_info)))
+ goto cleanup;
+
+ /* 2. Initialize a 32-bit, big-endian bit string counter as 1.
+ * 3. For i = 1 to reps by 1, do the following:
+ * - Compute Hashi = H(counter || Z || OtherInfo).
+ * - Increment counter (modulo 2^32)
+ */
+ for (counter = 1, offset = 0; ((counter <= reps) && (offset <= key_block->length)); counter++) {
+ EVP_MD_CTX c;
+ uint s = 0;
+ uint32_t be_counter = htonl(counter);
+
+ EVP_MD_CTX_init(&c);
+
+ /* - Compute Hashi = H(counter || Z || OtherInfo). */
+ if (0 == EVP_DigestInit(&c, EVP_func())) {
+ krb5_set_error_message(context, KRB5_CRYPTO_INTERNAL,
+ "Call to OpenSSL EVP_DigestInit() returned an error.");
+ retval = KRB5_CRYPTO_INTERNAL;
+ goto cleanup;
+ }
+
+ if ((0 == EVP_DigestUpdate(&c, &be_counter, 4)) ||
+ (0 == EVP_DigestUpdate(&c, secret->data, secret->length)) ||
+ (0 == EVP_DigestUpdate(&c, other_info->data, other_info->length))) {
+ krb5_set_error_message(context, KRB5_CRYPTO_INTERNAL,
+ "Call to OpenSSL EVP_DigestUpdate() returned an error.");
+ retval = KRB5_CRYPTO_INTERNAL;
+ goto cleanup;
+ }
+
+ /* 4. Set key = Hash1 || Hash2 || ... so that length of key is K bytes. */
+ if (0 == EVP_DigestFinal(&c, (rand_buf + offset), &s)) {
+ krb5_set_error_message(context, KRB5_CRYPTO_INTERNAL,
+ "Call to OpenSSL EVP_DigestUpdate() returned an error.");
+ retval = KRB5_CRYPTO_INTERNAL;
+ goto cleanup;
+ }
+ offset += s;
+
+ assert(s == hash_len); /* add a message to this assert? */
+
+ EVP_MD_CTX_cleanup(&c);
+ }
+
+ /* Reduce length of random data to key_len to avoid errors. */
+ random_data.length = key_block->length;
+ retval = krb5_c_random_to_key(context, enctype, &random_data,
+ key_block);
+
+cleanup:
+ /* If this has been an error, free the allocated key_block, if any */
+ if (retval) {
+ krb5_free_keyblock_contents(context, key_block);
+ }
+
+ /* free other allocated resources, either way */
+ if (rand_buf)
+ free(rand_buf);
+ krb5_free_data(context, other_info);
+ krb5_free_data(context, supp_pub_info);
+
+ return retval;
+} /*pkinit_alg_agility_kdf() */
+
/* Call DH_compute_key() and ensure that we left-pad short results instead of
* leaving junk bytes at the end of the buffer. */
static void
Copied: trunk/src/plugins/preauth/pkinit/pkinit_kdf_constants.c (from rev 25190, trunk/src/util/profile/test_load.c)
===================================================================
--- trunk/src/plugins/preauth/pkinit/pkinit_kdf_constants.c (rev 0)
+++ trunk/src/plugins/preauth/pkinit/pkinit_kdf_constants.c 2011-09-19 00:34:57 UTC (rev 25191)
@@ -0,0 +1,57 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* prototype/prototype.c */
+/*
+ * Copyright (C) 2011 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * pkinit_kdf_test.c -- Structures and constants for implementation of
+ * pkinit algorithm agility. Includes definitions of algorithm identifiers
+ * for SHA-1, SHA-256 and SHA-512.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "k5-platform.h"
+#include "krb5.h"
+#include "k5-int-pkinit.h"
+
+#include "pkinit.h"
+#include "pkinit_crypto.h"
+
+/* statically declare OID constants for all three algorithms */
+const krb5_octet krb5_pkinit_sha1_oid[10] =
+ {0x2B,0x06,0x01,0x05,0x02,0x03,0x06,0x01};
+const size_t krb5_pkinit_sha1_oid_len = 8;
+const krb5_octet krb5_pkinit_sha256_oid[10] =
+ {0x2B,0x06,0x01,0x05,0x02,0x03,0x06,0x02};
+const size_t krb5_pkinit_sha256_oid_len = 8;
+const krb5_octet krb5_pkinit_sha512_oid [10] =
+ {0x2B,0x06,0x01,0x05,0x02,0x03,0x06,0x03};
+const size_t krb5_pkinit_sha512_oid_len = 8;
Added: trunk/src/plugins/preauth/pkinit/pkinit_kdf_test.c
===================================================================
--- trunk/src/plugins/preauth/pkinit/pkinit_kdf_test.c (rev 0)
+++ trunk/src/plugins/preauth/pkinit/pkinit_kdf_test.c 2011-09-19 00:34:57 UTC (rev 25191)
@@ -0,0 +1,183 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* prototype/prototype.c */
+/*
+ * Copyright (C) 2011 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * pkinit_kdf_test.c -- Test to verify the correctness of the function
+ * pkinit_alg_agility_kdf() in pkinit_crypto_openssl, which implements
+ * the Key Derivation Function from the PKInit Algorithm Agility
+ * document, currently draft-ietf-krb-wg-pkinit-alg-agility-04.txt.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "k5-platform.h"
+
+#include "pkinit_crypto_openssl.h"
+
+/**
+ * Initialize a krb5_data from @a s, a constant string. Note @a s is evaluated
+ * multiple times; this is acceptable for constants.
+ */
+#define DATA_FROM_STRING(s) \
+ {0, sizeof(s)-1, (char *) s}
+
+
+/* values from the test vector in the pkinit-alg-agility draft */
+int secret_len = 256;
+char twenty_as[10];
+char eighteen_bs[9] ;
+char party_u_name [] = "lha at SU.SE";
+char party_v_name [] = "krbtgt/SU.SE at SU.SE";
+int enctype_value = 18;
+krb5_octet key_hex [] =
+ {0xC7, 0x62, 0x89, 0xEC, 0x4B, 0x28, 0xA6, 0x91,
+ 0xFF, 0xCE, 0x80, 0xBB, 0xB7, 0xEC, 0x82, 0x41,
+ 0x52, 0x3F, 0x99, 0xB1, 0x90, 0xCF, 0x2D, 0x34,
+ 0x8F, 0x54, 0xA8, 0x65, 0x81, 0x2C, 0x32, 0x73};
+const krb5_data lha_data = DATA_FROM_STRING("lha");
+const krb5_principal_data ticket_server = {
+ 0, /*magic*/
+ DATA_FROM_STRING("SU.SE"),
+ (krb5_data *) &lha_data,
+ 1, 1};
+const krb5_ticket test_ticket = {
+ KV5M_TICKET,
+ (krb5_principal) &ticket_server,
+ {0, /*magic*/
+ 18,
+ 0,
+ DATA_FROM_STRING("hejhej") },
+ NULL};
+
+
+
+int
+main (int argc,
+ char **argv)
+{
+ /* arguments for calls to pkinit_alg_agility_kdf() */
+ krb5_context context = 0;
+ krb5_octet_data secret;
+ krb5_algorithm_identifier alg_id;
+ krb5_enctype enctype = enctype_value;
+ krb5_octet_data as_req;
+ krb5_octet_data pk_as_rep;
+ krb5_keyblock key_block;
+
+ /* other local variables */
+ int retval = 0;
+ int max_keylen = 2048;
+ krb5_principal u_principal = NULL;
+ krb5_principal v_principal = NULL;
+ krb5_keyblock *key_block_ptr = &key_block;
+
+ /* initialize variables that get malloc'ed, so cleanup is safe */
+ krb5_init_context (&context);
+ memset (&alg_id, 0, sizeof(alg_id));
+ memset (&as_req, 0, sizeof(as_req));
+ memset (&pk_as_rep, 0, sizeof(pk_as_rep));
+ memset (&key_block, 0, sizeof(key_block));
+
+ /* set up algorithm id */
+ alg_id.algorithm.data = (unsigned char *) &krb5_pkinit_sha1_oid;
+ alg_id.algorithm.length = krb5_pkinit_sha1_oid_len;
+
+ /* set up a 256-byte, ALL-ZEROS secret */
+ if (NULL == (secret.data = malloc(secret_len))) {
+ printf("ERROR in pkinit_kdf_test: Memory allocation failed.");
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ secret.length = secret_len;
+ memset(secret.data, 0, secret_len);
+
+ /* set-up the partyUInfo and partyVInfo principals */
+ if ((0 != (retval = krb5_parse_name(context, party_u_name,
+ &u_principal)))
+ (0 != (retval = krb5_parse_name(context, party_v_name,
+ &v_principal)))) {
+ printf("ERROR in pkinit_kdf_test: Error parsing names, retval = %d",
+ retval);
+ goto cleanup;
+ }
+
+ /* set-up the as_req and and pk_as_rep data */
+ memset(twenty_as, 0xaa, sizeof(twenty_as));
+ memset(eighteen_bs, 0xbb, sizeof(eighteen_bs));
+ as_req.length = sizeof(twenty_as);
+ as_req.data = (unsigned char *)&twenty_as;
+
+ pk_as_rep.length = sizeof(eighteen_bs);
+ pk_as_rep.data = (unsigned char *)&eighteen_bs;
+
+ /* set-up the key_block */
+ if (0 != (retval = krb5_init_keyblock(context, enctype, max_keylen,
+ &key_block_ptr))) {
+ printf("ERROR in pkinit_kdf_test: can't init keybloc, retval = %d",
+ retval);
+ goto cleanup;
+
+ }
+
+ /* call krb5_pkinit_alg_agility_kdf() with test vector values*/
+ if (0 != (retval = pkinit_alg_agility_kdf(context, &secret, &alg_id,
+ u_principal, v_principal,
+ enctype, &as_req, &pk_as_rep,
+ &test_ticket, &key_block))) {
+ printf("ERROR in pkinit_kdf_test: kdf call failed, retval = %d",
+ retval);
+ goto cleanup;
+ }
+
+ /* compare key to expected key value */
+
+ if ((key_block.length == sizeof(key_hex)) &&
+ (0 == memcmp(key_block.contents, key_hex, key_block.length))) {
+ printf("SUCCESS: Correct key value generated!");
+ retval = 0;
+ }
+ else {
+ printf("FAILURE: Incorrect key value generated!");
+ retval = 1;
+ }
+
+ cleanup:
+ /* release all allocated resources, whether good or bad return */
+ if (secret.data)
+ free(secret.data);
+ if (u_principal)
+ free(u_principal);
+ if (v_principal)
+ free(v_principal);
+ krb5_free_keyblock_contents(context, &key_block);
+ exit(retval);
+}
More information about the cvs-krb5
mailing list