1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* kdc/cammac.c - Functions for wrapping and unwrapping CAMMACs */ 3 /* 4 * Copyright (C) 2015 by the Massachusetts Institute of Technology. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 30 * OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include "k5-int.h" 34 #include "kdc_util.h" 35 36 /* Encode enc_tkt with contents as the authdata field, for use in KDC 37 * verifier checksums. */ 38 static krb5_error_code 39 encode_kdcver_encpart(krb5_enc_tkt_part *enc_tkt, krb5_authdata **contents, 40 krb5_data **der_out) 41 { 42 krb5_enc_tkt_part ck_enctkt; 43 44 ck_enctkt = *enc_tkt; 45 ck_enctkt.authorization_data = contents; 46 return encode_krb5_enc_tkt_part(&ck_enctkt, der_out); 47 } 48 49 /* 50 * Create a CAMMAC for contents, using enc_tkt and tgt_key for the KDC 51 * verifier. tgt_key must be the decrypted first key data entry in tgt. Set 52 * *cammac_out to a single-element authdata list containing the CAMMAC inside 53 * an IF-RELEVANT container. 54 */ 55 krb5_error_code 56 cammac_create(krb5_context context, krb5_enc_tkt_part *enc_tkt, 57 krb5_keyblock *server_key, krb5_db_entry *tgt, 58 krb5_keyblock *tgt_key, krb5_authdata **contents, 59 krb5_authdata ***cammac_out) 60 { 61 krb5_error_code ret; 62 krb5_data *der_authdata = NULL, *der_enctkt = NULL, *der_cammac = NULL; 63 krb5_authdata ad, *list[2]; 64 krb5_cammac cammac; 65 krb5_verifier_mac kdc_verifier, svc_verifier; 66 krb5_keyblock tgtkey; 67 krb5_checksum kdc_cksum, svc_cksum; 68 69 *cammac_out = NULL; 70 memset(&tgtkey, 0, sizeof(tgtkey)); 71 memset(&kdc_cksum, 0, sizeof(kdc_cksum)); 72 memset(&svc_cksum, 0, sizeof(svc_cksum)); 73 74 /* Checksum the reply with contents as authdata for the KDC verifier. */ 75 ret = encode_kdcver_encpart(enc_tkt, contents, &der_enctkt); 76 if (ret) 77 goto cleanup; 78 ret = krb5_c_make_checksum(context, 0, tgt_key, KRB5_KEYUSAGE_CAMMAC, 79 der_enctkt, &kdc_cksum); 80 if (ret) 81 goto cleanup; 82 kdc_verifier.princ = NULL; 83 kdc_verifier.kvno = current_kvno(tgt); 84 kdc_verifier.enctype = ENCTYPE_NULL; 85 kdc_verifier.checksum = kdc_cksum; 86 87 /* Encode the authdata and checksum it for the service verifier. */ 88 ret = encode_krb5_authdata(contents, &der_authdata); 89 if (ret) 90 goto cleanup; 91 ret = krb5_c_make_checksum(context, 0, server_key, KRB5_KEYUSAGE_CAMMAC, 92 der_authdata, &svc_cksum); 93 if (ret) 94 goto cleanup; 95 svc_verifier.princ = NULL; 96 svc_verifier.kvno = 0; 97 svc_verifier.enctype = ENCTYPE_NULL; 98 svc_verifier.checksum = svc_cksum; 99 100 cammac.elements = contents; 101 cammac.kdc_verifier = &kdc_verifier; 102 cammac.svc_verifier = &svc_verifier; 103 cammac.other_verifiers = NULL; 104 105 ret = encode_krb5_cammac(&cammac, &der_cammac); 106 if (ret) 107 goto cleanup; 108 109 /* Wrap the encoded CAMMAC in an IF-RELEVANT container and return it as a 110 * single-element authdata list. */ 111 ad.ad_type = KRB5_AUTHDATA_CAMMAC; 112 ad.length = der_cammac->length; 113 ad.contents = (uint8_t *)der_cammac->data; 114 list[0] = &ad; 115 list[1] = NULL; 116 ret = krb5_encode_authdata_container(context, KRB5_AUTHDATA_IF_RELEVANT, 117 list, cammac_out); 118 119 cleanup: 120 krb5_free_data(context, der_enctkt); 121 krb5_free_data(context, der_authdata); 122 krb5_free_data(context, der_cammac); 123 krb5_free_keyblock_contents(context, &tgtkey); 124 krb5_free_checksum_contents(context, &kdc_cksum); 125 krb5_free_checksum_contents(context, &svc_cksum); 126 return ret; 127 } 128 129 /* 130 * Return true if cammac's KDC verifier is valid for enc_tkt, using tgt to 131 * retrieve the TGT key indicated by the verifier. tgt_key must be the 132 * decrypted first key data entry in tgt. 133 */ 134 krb5_boolean 135 cammac_check_kdcver(krb5_context context, krb5_cammac *cammac, 136 krb5_enc_tkt_part *enc_tkt, krb5_db_entry *tgt, 137 krb5_keyblock *tgt_key) 138 { 139 krb5_verifier_mac *ver = cammac->kdc_verifier; 140 krb5_key_data *kd; 141 krb5_keyblock tgtkey, *key; 142 krb5_boolean valid = FALSE; 143 krb5_data *der_enctkt = NULL; 144 145 memset(&tgtkey, 0, sizeof(tgtkey)); 146 147 if (ver == NULL) 148 goto cleanup; 149 150 /* Fetch the krbtgt key indicated by the KDC verifier. Only allow the 151 * first krbtgt key of the specified kvno. */ 152 if (ver->kvno == current_kvno(tgt)) { 153 key = tgt_key; 154 } else { 155 if (krb5_dbe_find_enctype(context, tgt, -1, -1, ver->kvno, &kd) != 0) 156 goto cleanup; 157 if (krb5_dbe_decrypt_key_data(context, NULL, kd, &tgtkey, NULL) != 0) 158 goto cleanup; 159 key = &tgtkey; 160 } 161 if (ver->enctype != ENCTYPE_NULL && tgtkey.enctype != ver->enctype) 162 goto cleanup; 163 164 /* Verify the checksum over the DER-encoded enc_tkt with the CAMMAC 165 * elements as authdata. */ 166 if (encode_kdcver_encpart(enc_tkt, cammac->elements, &der_enctkt) != 0) 167 goto cleanup; 168 (void)krb5_c_verify_checksum(context, key, KRB5_KEYUSAGE_CAMMAC, 169 der_enctkt, &ver->checksum, &valid); 170 171 cleanup: 172 krb5_free_keyblock_contents(context, &tgtkey); 173 krb5_free_data(context, der_enctkt); 174 return valid; 175 } 176