diff options
Diffstat (limited to 'src/lib/krb5')
-rw-r--r-- | src/lib/krb5/krb/deps | 5 | ||||
-rw-r--r-- | src/lib/krb5/krb/int-proto.h | 3 | ||||
-rw-r--r-- | src/lib/krb5/krb/pac.c | 148 | ||||
-rw-r--r-- | src/lib/krb5/krb/pac_sign.c | 121 | ||||
-rw-r--r-- | src/lib/krb5/krb/t_pac.c | 182 | ||||
-rw-r--r-- | src/lib/krb5/libkrb5.exports | 2 |
6 files changed, 455 insertions, 6 deletions
diff --git a/src/lib/krb5/krb/deps b/src/lib/krb5/krb/deps index 6197a98..ca6ab25 100644 --- a/src/lib/krb5/krb/deps +++ b/src/lib/krb5/krb/deps @@ -710,7 +710,7 @@ pac.so pac.po $(OUTPRE)pac.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/k5-utf8.h $(top_srcdir)/include/krb5.h \ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - authdata.h pac.c + authdata.h int-proto.h pac.c pac_sign.so pac_sign.po $(OUTPRE)pac_sign.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ @@ -721,7 +721,8 @@ pac_sign.so pac_sign.po $(OUTPRE)pac_sign.$(OBJEXT): \ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/k5-utf8.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h authdata.h pac_sign.c + $(top_srcdir)/include/socket-utils.h authdata.h int-proto.h \ + pac_sign.c padata.so padata.po $(OUTPRE)padata.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h index 15f4adf..b62f904 100644 --- a/src/lib/krb5/krb/int-proto.h +++ b/src/lib/krb5/krb/int-proto.h @@ -395,4 +395,7 @@ k5_sname_wildcard_host(krb5_context context, krb5_const_principal mprinc); krb5_int32 k5_infer_principal_type(krb5_principal princ); +krb5_boolean +k5_pac_should_have_ticket_signature(krb5_const_principal sprinc); + #endif /* KRB5_INT_FUNC_PROTO__ */ diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c index 5118bf7..ab1606d 100644 --- a/src/lib/krb5/krb/pac.c +++ b/src/lib/krb5/krb/pac.c @@ -25,6 +25,7 @@ */ #include "k5-int.h" +#include "int-proto.h" #include "authdata.h" /* draft-brezak-win2k-krb-authz-00 */ @@ -537,8 +538,10 @@ k5_pac_verify_server_checksum(krb5_context context, checksum.checksum_type = load_32_le(p); checksum.length = checksum_data.length - PAC_SIGNATURE_DATA_LENGTH; checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH; + if (checksum.checksum_type == CKSUMTYPE_SHA1) + return KRB5KDC_ERR_SUMTYPE_NOSUPP; if (!krb5_c_is_keyed_cksum(checksum.checksum_type)) - return KRB5KRB_AP_ERR_INAPP_CKSUM; + return KRB5KRB_ERR_GENERIC; pac_data.length = pac->data.length; pac_data.data = k5memdup(pac->data.data, pac->data.length, &ret); @@ -571,7 +574,7 @@ k5_pac_verify_server_checksum(krb5_context context, } if (valid == FALSE) - ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + ret = KRB5KRB_AP_ERR_MODIFIED; return ret; } @@ -607,7 +610,7 @@ k5_pac_verify_kdc_checksum(krb5_context context, p = (krb5_octet *)privsvr_checksum.data; checksum.checksum_type = load_32_le(p); if (!krb5_c_is_keyed_cksum(checksum.checksum_type)) - return KRB5KRB_AP_ERR_INAPP_CKSUM; + return KRB5KRB_ERR_GENERIC; /* There may be an RODCIdentifier trailer (see [MS-PAC] 2.8), so look up * the length of the checksum by its type. */ @@ -629,11 +632,148 @@ k5_pac_verify_kdc_checksum(krb5_context context, return ret; if (valid == FALSE) - ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + ret = KRB5KRB_AP_ERR_MODIFIED; return ret; } +static krb5_error_code +verify_ticket_checksum(krb5_context context, const krb5_pac pac, + const krb5_data *ticket, const krb5_keyblock *privsvr) +{ + krb5_error_code ret; + krb5_checksum checksum; + krb5_data checksum_data; + krb5_boolean valid; + krb5_octet *p; + + ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_TICKET_CHECKSUM, + &checksum_data); + if (ret != 0) + return KRB5KRB_AP_ERR_MODIFIED; + + if (checksum_data.length < PAC_SIGNATURE_DATA_LENGTH) + return KRB5_BAD_MSIZE; + + p = (krb5_octet *)checksum_data.data; + checksum.checksum_type = load_32_le(p); + checksum.length = checksum_data.length - PAC_SIGNATURE_DATA_LENGTH; + checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH; + if (!krb5_c_is_keyed_cksum(checksum.checksum_type)) + return KRB5KRB_ERR_GENERIC; + + ret = krb5_c_verify_checksum(context, privsvr, + KRB5_KEYUSAGE_APP_DATA_CKSUM, ticket, + &checksum, &valid); + if (ret != 0) + return ret; + + return valid ? 0 : KRB5KRB_AP_ERR_MODIFIED; +} + +/* Per MS-PAC 2.8.3, tickets encrypted to TGS and password change principals + * should not have ticket signatures. */ +krb5_boolean +k5_pac_should_have_ticket_signature(krb5_const_principal sprinc) +{ + if (IS_TGS_PRINC(sprinc)) + return FALSE; + if (sprinc->length == 2 && data_eq_string(sprinc->data[0], "kadmin") && + data_eq_string(sprinc->data[1], "changepw")) + return FALSE; + return TRUE; +} + +krb5_error_code KRB5_CALLCONV +krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt, + krb5_const_principal server_princ, + const krb5_keyblock *server, + const krb5_keyblock *privsvr, krb5_pac *pac_out) +{ + krb5_error_code ret; + krb5_pac pac = NULL; + krb5_data *recoded_tkt = NULL; + krb5_authdata **authdata, *orig, **ifrel = NULL, **recoded_ifrel = NULL; + uint8_t z = 0; + krb5_authdata zpac = { KV5M_AUTHDATA, KRB5_AUTHDATA_WIN2K_PAC, 1, &z }; + size_t i, j; + + *pac_out = NULL; + + /* + * Find the position of the PAC in the ticket authdata. ifrel will be the + * decoded AD-IF-RELEVANT container at position i containing a PAC, and j + * will be the offset within the container. + */ + authdata = enc_tkt->authorization_data; + for (i = 0; authdata != NULL && authdata[i] != NULL; i++) { + if (authdata[i]->ad_type != KRB5_AUTHDATA_IF_RELEVANT) + continue; + + ret = krb5_decode_authdata_container(context, + KRB5_AUTHDATA_IF_RELEVANT, + authdata[i], &ifrel); + if (ret) + goto cleanup; + + for (j = 0; ifrel[j] != NULL; j++) { + if (ifrel[j]->ad_type == KRB5_AUTHDATA_WIN2K_PAC) + break; + } + if (ifrel[j] != NULL) + break; + + krb5_free_authdata(context, ifrel); + ifrel = NULL; + } + + /* Stop and return successfully if we didn't find a PAC. */ + if (ifrel == NULL) { + ret = 0; + goto cleanup; + } + + ret = krb5_pac_parse(context, ifrel[j]->contents, ifrel[j]->length, &pac); + if (ret) + goto cleanup; + + if (privsvr != NULL && k5_pac_should_have_ticket_signature(server_princ)) { + /* To check the PAC ticket signatures, re-encode the ticket with the + * PAC contents replaced by a single zero. */ + orig = ifrel[j]; + ifrel[j] = &zpac; + ret = krb5_encode_authdata_container(context, + KRB5_AUTHDATA_IF_RELEVANT, + ifrel, &recoded_ifrel); + ifrel[j] = orig; + if (ret) + goto cleanup; + orig = authdata[i]; + authdata[i] = recoded_ifrel[0]; + ret = encode_krb5_enc_tkt_part(enc_tkt, &recoded_tkt); + authdata[i] = orig; + if (ret) + goto cleanup; + + ret = verify_ticket_checksum(context, pac, recoded_tkt, privsvr); + if (ret) + goto cleanup; + } + + ret = krb5_pac_verify_ext(context, pac, enc_tkt->times.authtime, NULL, + server, privsvr, FALSE); + + *pac_out = pac; + pac = NULL; + +cleanup: + krb5_pac_free(context, pac); + krb5_free_data(context, recoded_tkt); + krb5_free_authdata(context, ifrel); + krb5_free_authdata(context, recoded_ifrel); + return ret; +} + krb5_error_code KRB5_CALLCONV krb5_pac_verify(krb5_context context, const krb5_pac pac, diff --git a/src/lib/krb5/krb/pac_sign.c b/src/lib/krb5/krb/pac_sign.c index 12f0259..0f9581a 100644 --- a/src/lib/krb5/krb/pac_sign.c +++ b/src/lib/krb5/krb/pac_sign.c @@ -25,6 +25,7 @@ */ #include "k5-int.h" +#include "int-proto.h" #include "authdata.h" /* draft-brezak-win2k-krb-authz-00 */ @@ -286,3 +287,123 @@ krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime, return 0; } + +/* Add a signature over der_enc_tkt in privsvr to pac. der_enc_tkt should be + * encoded with a dummy PAC authdata element containing a single zero byte. */ +static krb5_error_code +add_ticket_signature(krb5_context context, const krb5_pac pac, + krb5_data *der_enc_tkt, const krb5_keyblock *privsvr) +{ + krb5_error_code ret; + krb5_data ticket_cksum; + krb5_cksumtype ticket_cksumtype; + krb5_crypto_iov iov[2]; + + /* Create zeroed buffer for checksum. */ + ret = k5_insert_checksum(context, pac, KRB5_PAC_TICKET_CHECKSUM, + privsvr, &ticket_cksumtype); + if (ret) + return ret; + + ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_TICKET_CHECKSUM, + &ticket_cksum); + if (ret) + return ret; + + iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + iov[0].data = *der_enc_tkt; + iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM; + iov[1].data = make_data(ticket_cksum.data + PAC_SIGNATURE_DATA_LENGTH, + ticket_cksum.length - PAC_SIGNATURE_DATA_LENGTH); + ret = krb5_c_make_checksum_iov(context, ticket_cksumtype, privsvr, + KRB5_KEYUSAGE_APP_DATA_CKSUM, iov, 2); + if (ret) + return ret; + + store_32_le(ticket_cksumtype, ticket_cksum.data); + return 0; +} + +/* Set *out to an AD-IF-RELEVANT authdata element containing a PAC authdata + * element with contents pac_data. */ +static krb5_error_code +encode_pac_ad(krb5_context context, krb5_data *pac_data, krb5_authdata **out) +{ + krb5_error_code ret; + krb5_authdata *container[2], **encoded_container = NULL; + krb5_authdata pac_ad = { KV5M_AUTHDATA, KRB5_AUTHDATA_WIN2K_PAC }; + uint8_t z = 0; + + pac_ad.contents = (pac_data != NULL) ? (uint8_t *)pac_data->data : &z; + pac_ad.length = (pac_data != NULL) ? pac_data->length : 1; + container[0] = &pac_ad; + container[1] = NULL; + + ret = krb5_encode_authdata_container(context, KRB5_AUTHDATA_IF_RELEVANT, + container, &encoded_container); + if (ret) + return ret; + + *out = encoded_container[0]; + free(encoded_container); + return 0; +} + +krb5_error_code KRB5_CALLCONV +krb5_kdc_sign_ticket(krb5_context context, krb5_enc_tkt_part *enc_tkt, + const krb5_pac pac, krb5_const_principal server_princ, + krb5_const_principal client_princ, + const krb5_keyblock *server, const krb5_keyblock *privsvr, + krb5_boolean with_realm) +{ + krb5_error_code ret; + krb5_data *der_enc_tkt = NULL, pac_data = empty_data(); + krb5_authdata **list, *pac_ad; + size_t count; + + /* Reallocate space for another authdata element in enc_tkt. */ + list = enc_tkt->authorization_data; + for (count = 0; list != NULL && list[count] != NULL; count++); + list = realloc(enc_tkt->authorization_data, (count + 2) * sizeof(*list)); + if (list == NULL) + return ENOMEM; + list[count] = NULL; + enc_tkt->authorization_data = list; + + /* Create a dummy PAC for ticket signing and make it the first element. */ + ret = encode_pac_ad(context, NULL, &pac_ad); + if (ret) + goto cleanup; + memmove(list + 1, list, (count + 1) * sizeof(*list)); + list[0] = pac_ad; + + if (k5_pac_should_have_ticket_signature(server_princ)) { + ret = encode_krb5_enc_tkt_part(enc_tkt, &der_enc_tkt); + if (ret) + goto cleanup; + + assert(privsvr != NULL); + ret = add_ticket_signature(context, pac, der_enc_tkt, privsvr); + if (ret) + goto cleanup; + } + + ret = krb5_pac_sign_ext(context, pac, enc_tkt->times.authtime, + client_princ, server, privsvr, with_realm, + &pac_data); + if (ret) + goto cleanup; + + /* Replace the dummy PAC with the signed real one. */ + ret = encode_pac_ad(context, &pac_data, &pac_ad); + if (ret) + goto cleanup; + free(list[0]->contents); + free(list[0]); + list[0] = pac_ad; + +cleanup: + krb5_free_data(context, der_enc_tkt); + krb5_free_data_contents(context, &pac_data); + return ret; +} diff --git a/src/lib/krb5/krb/t_pac.c b/src/lib/krb5/krb/t_pac.c index ee47152..0b1b1f0 100644 --- a/src/lib/krb5/krb/t_pac.c +++ b/src/lib/krb5/krb/t_pac.c @@ -595,6 +595,186 @@ check_pac(krb5_context context, int index, const unsigned char *pdata, krb5_pac_free(context, pac); } +static const krb5_keyblock ticket_sig_krbtgt_key = { + 0, ENCTYPE_AES256_CTS_HMAC_SHA1_96, + 32, U("\x7a\x58\x98\xd2\xaf\xa6\xaf\xc0\x6a\xce\x06\x04\x4b\xc2\x70\x84" + "\x9b\x8e\x0a\x6c\x4c\x07\xdc\x6f\xbb\x48\x43\xe1\xd2\xaa\x97\xf7") +}; + +static const krb5_keyblock ticket_sig_server_key = { + 0, ENCTYPE_ARCFOUR_HMAC, + 16, U("\xed\x23\x11\x20\x7a\x21\x44\x20\xbf\xc0\x8d\x36\xf7\xf6\xb2\x3e") +}; + +static const krb5_data ticket_data = { + .length = 972, .data = + "\x61\x82\x03\xC8\x30\x82\x03\xC4\xA0\x03\x02\x01\x05\xA1\x0A\x1B" + "\x08\x43\x44\x4F\x4D\x2E\x43\x4F\x4D\xA2\x0F\x30\x0D\xA0\x03\x02" + "\x01\x01\xA1\x06\x30\x04\x1B\x02\x73\x31\xA3\x82\x03\x9E\x30\x82" + "\x03\x9A\xA0\x03\x02\x01\x17\xA1\x03\x02\x01\x03\xA2\x82\x03\x8C" + "\x04\x82\x03\x88\x44\x31\x61\x20\x17\xC9\xFE\xBC\xAC\x46\xB5\x77" + "\xE9\x68\x04\x4C\x9B\x31\x91\x0C\xC1\xD4\xDD\xEF\xC7\x34\x20\x08" + "\x90\x91\xE8\x79\xE0\xB5\x03\x26\xA4\x65\xDE\xEC\x47\x03\x2A\x8F" + "\x61\xE7\x4D\x38\x5A\x42\x95\x5A\xF9\x2F\x41\x2C\x2A\x6E\x60\xA1" + "\xEB\x51\xB3\xBD\x4C\x00\x41\x2A\x44\x76\x08\x37\x1A\x51\xFD\x65" + "\x67\x7E\xBF\x3D\x90\x86\xE3\x9A\x54\x6B\x67\xA8\x08\x7A\x73\xCC" + "\xC3\xB7\x4B\xD5\x5C\x3A\x14\x6C\xC1\x5F\x54\x4B\x92\x55\xB4\xB7" + "\x92\x23\x3F\x53\x89\x47\x8E\x1F\x8B\xB9\xDB\x3B\x93\xE8\x70\xE4" + "\x24\xB8\x9D\xF0\x0E\x35\x28\xF8\x7A\x27\x5D\xF7\x25\x97\x9C\xF5" + "\x9F\x9F\x64\x04\xF2\xA3\xAB\x11\x15\xB6\xDA\x18\xD6\x46\xD5\xE6" + "\xB8\x08\xDE\x0A\x62\xFD\xF8\xAA\x52\x90\xD9\x67\x29\xB2\xCD\x06" + "\xB6\xB0\x50\x2B\x3F\x0F\xA3\xA5\xBF\xAA\x6E\x40\x03\xD6\x5F\x02" + "\xBC\xD8\x18\x47\x97\x09\xD7\xE4\x96\x3B\xCB\xEB\x92\x2C\x3C\x49" + "\xFF\x1F\x71\xE0\x52\x94\x0F\x8B\x9F\xB8\x2A\xBB\x9C\xE2\xA3\xDD" + "\x38\x89\xE2\xB1\x0B\x9E\x1F\x7A\xB3\xE3\xD2\xB0\x94\xDC\x87\xBE" + "\x37\xA6\xD3\xB3\x29\x35\x9A\x72\xC3\x7A\xF1\xA9\xE6\xC5\xD1\x26" + "\x83\x65\x44\x17\xBA\x55\xA8\x5E\x94\x26\xED\xE9\x8A\x93\x11\x5D" + "\x7E\x20\x1B\x9C\x15\x9E\x13\x37\x03\x4D\xDD\x99\x51\xD8\x66\x29" + "\x6A\xB9\xFB\x49\xFE\x52\x78\xDA\x86\x85\xA9\xA3\xB9\xEF\xEC\xAD" + "\x35\xA6\x8D\xAC\x0F\x75\x22\xBB\x0B\x49\x1C\x13\x52\x40\xC9\x52" + "\x69\x09\x54\xD1\x0F\x94\x3F\x22\x48\x67\xB0\x96\x28\xAA\xE6\x28" + "\xD9\x0C\x08\xEF\x51\xED\x15\x5E\xA2\x53\x59\xA5\x03\xB4\x06\x20" + "\x3D\xCC\xB4\xC5\xF8\x8C\x73\x67\xA3\x21\x3D\x19\xCD\xD4\x12\x28" + "\xD2\x93\xDE\x0D\xF0\x71\x10\x50\xD6\x33\x35\x04\x11\x64\x43\x39" + "\xC3\xDF\x96\xE3\x66\xE3\x85\xCA\xE7\x67\x14\x3A\xF0\x43\xAA\xBB" + "\xD4\x1D\xB5\x24\xB5\x74\x90\x25\xA7\x87\x7E\xDB\xD3\x83\x8A\x3A" + "\x69\xA8\x2D\xAF\xB7\xB8\xF3\xDC\x13\xAF\x45\x61\x3F\x59\x39\x7E" + "\x69\xDE\x0C\x04\xF1\x10\x6B\xB4\x56\xFA\x21\x9F\x72\x2B\x60\x86" + "\xE3\x23\x0E\xC4\x51\xF6\xBE\xD8\xE1\x5F\xEE\x73\x4C\x17\x4C\x2C" + "\x1B\xFB\x9F\x1F\x7A\x3B\x07\x5B\x8E\xF1\x01\xAC\xD6\x30\x94\x8A" + "\x5D\x22\x6F\x08\xCE\xED\x5E\xB6\xDB\x86\x8C\x87\xEB\x8D\x91\xFF" + "\x0A\x86\x30\xBD\xC0\xF8\x25\xE7\xAE\x24\x35\xF2\xFC\xE5\xFD\x1B" + "\xB0\x05\x4A\xA3\xE5\xEB\x2E\x05\xAD\x99\x67\x49\x87\xE6\xB3\x87" + "\x82\xA4\x59\xA7\x6E\xDD\xF2\xB6\x66\xE8\xF7\x70\xF5\xBD\xC9\x0E" + "\xFA\x9C\x79\x84\xD4\x9B\x05\x0E\xBB\xF5\xDB\xEF\xFC\xCC\x26\xF2" + "\x93\xCF\xD2\x04\x3C\xA9\x2C\x65\x42\x97\x86\xD8\x38\x0A\x1E\xF6" + "\xD6\xCA\x30\xB5\x1A\xEC\xFB\xBA\x3B\x84\x57\xB0\xFD\xFB\xE6\xBC" + "\xF2\x76\xF6\x4C\xBB\xAB\xB1\x31\xA1\x27\x7C\xE6\xE6\x81\xB6\xCE" + "\x84\x86\x40\xB6\x40\x33\xC4\xF8\xB4\x15\xCF\xAA\xA5\x51\x78\xB9" + "\x8B\x50\x25\xB2\x88\x86\x96\x72\x8C\x71\x4D\xB5\x3A\x94\x86\x77" + "\x0E\x95\x9B\x16\x93\xEF\x3A\x11\x79\xBA\x83\xF7\x74\xD3\x8D\xBA" + "\x15\xE1\x2C\x04\x57\xA8\x92\x1E\x9D\x00\x8E\x20\xFD\x30\x70\xE7" + "\xF5\x65\x2F\x19\x0C\x94\xBA\x03\x71\x12\x96\xCD\xC8\xB4\x96\xDB" + "\xCE\x19\xC2\xDF\x3C\xC2\xF6\x3D\x53\xED\x98\xA5\x41\x72\x2A\x22" + "\x7B\xF3\x2B\x17\x6C\xE1\x39\x7D\xAE\x9B\x11\xF9\xC1\xA6\x9E\x9F" + "\x89\x3C\x12\xAA\x94\x74\xA7\x4F\x70\xE8\xB9\xDE\x04\xF0\x9D\x39" + "\x24\x2D\x92\xE8\x46\x2D\x2E\xF0\x40\x66\x1A\xD9\x27\xF9\x98\xF1" + "\x81\x1D\x70\x62\x63\x30\x6D\xCD\x84\x04\x5F\xFA\x83\xD3\xEC\x8D" + "\x86\xFB\x40\x61\xC1\x8A\x45\xFF\x7B\xD9\xD4\x18\x61\x7F\x51\xE3" + "\xFC\x1E\x18\xF0\xAF\xC6\x18\x2C\xE1\x6D\x5D\xF9\x62\xFC\x20\xA3" + "\xB2\x8A\x5F\xE5\xBB\x29\x0F\x99\x63\x07\x88\x38\x3A\x3B\x73\x2A" + "\x6D\xDA\x3D\xA8\x0D\x8F\x56\x41\x89\x82\xE5\xB8\x61\x00\x64\x7D" + "\x17\x0C\xCE\x03\x55\x8F\xF4\x5B\x0D\x50\xF2\xEB\x05\x67\xBE\xDB" + "\x7B\x75\xC5\xEA\xA1\xAB\x1D\xB0\x3C\x6D\x42\x08\x0B\x9A\x45\x20" + "\xA8\x8F\xE5\x67\x47\x30\xDE\x93\x5F\x43\x05\xEB\xA8\x2D\x80\xF5" + "\x1A\xB8\x4A\x4E\x42\x2D\x0B\x7A\xDC\x46\x20\x2D\x13\x17\xDD\x4B" + "\x94\x96\xAA\x1F\x06\x0C\x1F\x62\x07\x9C\x40\xA1" +}; + +static void +test_pac_ticket_signature(krb5_context context) +{ + krb5_error_code ret; + krb5_ticket *ticket; + krb5_principal sprinc; + krb5_authdata **authdata1, **authdata2; + krb5_pac pac, pac2, pac3; + uint32_t *list; + size_t len, i; + krb5_data data; + + ret = krb5_decode_ticket(&ticket_data, &ticket); + if (ret) + err(context, ret, "while decoding ticket"); + + ret = krb5_decrypt_tkt_part(context, &ticket_sig_server_key, ticket); + if (ret) + err(context, ret, "while decrypting ticket"); + + ret = krb5_parse_name(context, "s1@CDOM.COM", &sprinc); + if (ret) + err(context, ret, "krb5_parse_name"); + + ret = krb5_kdc_verify_ticket(context, ticket->enc_part2, sprinc, + &ticket_sig_server_key, + &ticket_sig_krbtgt_key, &pac); + if (ret) + err(context, ret, "while verifying ticket"); + + /* In this test, the server is also the client. */ + ret = krb5_pac_verify(context, pac, ticket->enc_part2->times.authtime, + ticket->server, NULL, NULL); + if (ret) + err(context, ret, "while verifying PAC client info"); + + /* We know there is only a PAC in this test's ticket. */ + authdata1 = ticket->enc_part2->authorization_data; + ticket->enc_part2->authorization_data = NULL; + + ret = krb5_kdc_sign_ticket(context, ticket->enc_part2, pac, sprinc, + sprinc, &ticket_sig_server_key, + &ticket_sig_krbtgt_key, FALSE); + if (ret) + err(context, ret, "while signing ticket"); + + authdata2 = ticket->enc_part2->authorization_data; + assert(authdata2 != NULL); + assert(authdata2[1] == NULL); + + assert(authdata1[0]->length == authdata2[0]->length); + assert(memcmp(authdata1[0]->contents, authdata2[0]->contents, + authdata1[0]->length) == 0); + + /* Test adding signatures to a new PAC. */ + ret = krb5_pac_init(context, &pac2); + if (ret) + err(context, ret, "krb5_pac_init"); + + ret = krb5_pac_get_types(context, pac, &len, &list); + if (ret) + err(context, ret, "krb5_pac_get_types"); + + for (i = 0; i < len; i++) { + /* Skip server_cksum, privsvr_cksum, and ticket_cksum. */ + if (list[i] == 6 || list[i] == 7 || list[i] == 16) + continue; + + ret = krb5_pac_get_buffer(context, pac, list[i], &data); + if (ret) + err(context, ret, "krb5_pac_get_buffer"); + + ret = krb5_pac_add_buffer(context, pac2, list[i], &data); + if (ret) + err(context, ret, "krb5_pac_add_buffer"); + + krb5_free_data_contents(context, &data); + } + free(list); + + krb5_free_authdata(context, authdata1); + krb5_free_authdata(context, ticket->enc_part2->authorization_data); + ticket->enc_part2->authorization_data = NULL; + + ret = krb5_kdc_sign_ticket(context, ticket->enc_part2, pac2, sprinc, NULL, + &ticket_sig_server_key, &ticket_sig_krbtgt_key, + FALSE); + if (ret) + err(context, ret, "while signing ticket"); + + /* We can't compare the data since the order of the buffers may differ. */ + ret = krb5_kdc_verify_ticket(context, ticket->enc_part2, sprinc, + &ticket_sig_server_key, + &ticket_sig_krbtgt_key, &pac3); + if (ret) + err(context, ret, "while verifying ticket"); + + krb5_pac_free(context, pac); + krb5_pac_free(context, pac2); + krb5_pac_free(context, pac3); + krb5_free_principal(context, sprinc); + krb5_free_ticket(context, ticket); +} + int main(int argc, char **argv) { @@ -608,6 +788,8 @@ main(int argc, char **argv) if (ret) err(NULL, 0, "krb5_init_contex"); + test_pac_ticket_signature(context); + ret = krb5_set_default_realm(context, "WIN2K3.THINKER.LOCAL"); if (ret) err(context, ret, "krb5_set_default_realm"); diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports index 0a05521..9a7a16f 100644 --- a/src/lib/krb5/libkrb5.exports +++ b/src/lib/krb5/libkrb5.exports @@ -465,6 +465,8 @@ krb5_is_permitted_enctype krb5_is_referral_realm krb5_is_thread_safe krb5_kdc_rep_decrypt_proc +krb5_kdc_sign_ticket +krb5_kdc_verify_ticket krb5_kt_add_entry krb5_kt_client_default krb5_kt_close |