Change export warning notice from "is assumed to require an export license"
[krb5.git] / src / lib / krb5 / krb / mk_req_ext.c
1 /*
2  * $Source$
3  * $Author$
4  *
5  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
6  * All Rights Reserved.
7  *
8  * Export of this software from the United States of America may
9  *   require a specific license from the United States Government.
10  *   It is the responsibility of any person or organization contemplating
11  *   export to obtain such a license before exporting.
12  * 
13  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14  * distribute this software and its documentation for any purpose and
15  * without fee is hereby granted, provided that the above copyright
16  * notice appear in all copies and that both that copyright notice and
17  * this permission notice appear in supporting documentation, and that
18  * the name of M.I.T. not be used in advertising or publicity pertaining
19  * to distribution of the software without specific, written prior
20  * permission.  M.I.T. makes no representations about the suitability of
21  * this software for any purpose.  It is provided "as is" without express
22  * or implied warranty.
23  * 
24  *
25  * krb5_mk_req_extended()
26  */
27
28 #if !defined(lint) && !defined(SABER)
29 static char rcsid_mk_req_ext_c[] =
30 "$Id$";
31 #endif  /* !lint & !SABER */
32
33 #include <krb5/krb5.h>
34 #include <krb5/asn1.h>
35
36 #include <krb5/libos.h>
37 #include <krb5/los-proto.h>
38
39 #include <krb5/ext-proto.h>
40
41 /*
42  Formats a KRB_AP_REQ message into outbuf, with more complete options than
43  krb_mk_req.
44
45  outbuf, ap_req_options, checksum, and ccache are used in the
46  same fashion as for krb5_mk_req.
47
48  creds is used to supply the credentials (ticket and session key) needed
49  to form the request.
50
51  if creds->ticket has no data (length == 0), then a ticket is obtained
52  from either the cache or the TGS, passing creds to krb5_get_credentials().
53  kdc_options specifies the options requested for the ticket to be used.
54  If a ticket with appropriate flags is not found in the cache, then these
55  options are passed on in a request to an appropriate KDC.
56
57  ap_req_options specifies the KRB_AP_REQ options desired.
58
59  if ap_req_options specifies AP_OPTS_USE_SESSION_KEY, then creds->ticket
60  must contain the appropriate ENC-TKT-IN-SKEY ticket.
61
62  checksum specifies the checksum to be used in the authenticator.
63
64  The outbuf buffer storage is allocated, and should be freed by the
65  caller when finished.
66
67  On an error return, the credentials pointed to by creds might have been
68  augmented with additional fields from the obtained credentials; the entire
69  credentials should be released by calling krb5_free_creds().
70
71  returns system errors
72 */
73 static krb5_error_code generate_authenticator PROTOTYPE((krb5_authenticator *,
74                                                          const krb5_creds *,
75                                                          const krb5_checksum *,
76                                                          krb5_keyblock *,
77                                                          krb5_int32 ));
78
79 krb5_error_code
80 krb5_mk_req_extended(ap_req_options, checksum, kdc_options,
81                      sequence, newkey, ccache, creds, authentp, outbuf)
82 const krb5_flags ap_req_options;
83 const krb5_checksum *checksum;
84 const krb5_flags kdc_options;
85 krb5_int32 sequence;
86 krb5_keyblock **newkey;
87 krb5_ccache ccache;
88 krb5_creds *creds;
89 krb5_authenticator *authentp;
90 krb5_data *outbuf;
91 {
92     krb5_error_code retval;
93     krb5_ap_req request;
94     krb5_authenticator authent;
95     krb5_data *scratch;
96     krb5_enctype etype;
97     krb5_encrypt_block eblock;
98     krb5_data *toutbuf;
99
100     if ((ap_req_options & AP_OPTS_USE_SESSION_KEY) &&
101         !creds->ticket.length)
102         return(KRB5_NO_TKT_SUPPLIED);
103
104     if (!creds->ticket.length) {
105         /* go get creds */
106         if (retval = krb5_get_credentials(kdc_options,
107                                           ccache,
108                                           creds))
109             return(retval);
110     }
111     /* verify a valid etype is available */
112     if (!valid_keytype(creds->keyblock.keytype))
113         return KRB5_PROG_KEYTYPE_NOSUPP;
114
115     etype = krb5_keytype_array[creds->keyblock.keytype]->system->proto_enctype;
116
117     if (!valid_etype(etype))
118         return KRB5_PROG_ETYPE_NOSUPP;
119
120     request.ap_options = ap_req_options;
121     /* we need a native ticket */
122     if (retval = decode_krb5_ticket(&creds->ticket, &request.ticket))
123         return(retval);
124
125 #define cleanup_ticket() krb5_free_ticket(request.ticket)
126     if (newkey) {
127         if (retval = krb5_generate_subkey(&creds->keyblock, newkey)) {
128             cleanup_ticket();
129             return retval;
130         }
131     }
132 #define cleanup_key() {if (newkey) krb5_free_keyblock(*newkey);}
133     if (retval = generate_authenticator(&authent, creds, checksum,
134                                         newkey ? *newkey : 0,
135                                         sequence)) {
136         cleanup_key();
137         cleanup_ticket();
138         return retval;
139     }
140     if (authentp) {
141             *authentp = authent;
142             /* Null out these fields, to prevent pointer sharing problems 
143              * The caller won't need these fields anyway, since they were
144              * supplied by the caller
145              */
146             authentp->client = NULL;
147             authentp->checksum = NULL; 
148     }
149     /* encode it before encrypting */
150     retval = encode_krb5_authenticator(&authent, &scratch);
151     if (retval) {
152         cleanup_key();
153         cleanup_ticket();
154         return(retval);
155     }
156
157 #define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); \
158 krb5_free_data(scratch); }
159
160     /* put together an eblock for this encryption */
161
162     krb5_use_cstype(&eblock, etype);
163     request.authenticator.etype = etype;
164     request.authenticator.kvno = 0; /* XXX user set? */
165     request.authenticator.ciphertext.length =
166         krb5_encrypt_size(scratch->length, eblock.crypto_entry);
167     /* add padding area, and zero it */
168     if (!(scratch->data = realloc(scratch->data,
169                                   request.authenticator.ciphertext.length))) {
170         /* may destroy scratch->data */
171         xfree(scratch);
172         retval = ENOMEM;
173         goto clean_ticket;
174     }
175     memset(scratch->data + scratch->length, 0,
176           request.authenticator.ciphertext.length - scratch->length);
177     if (!(request.authenticator.ciphertext.data =
178           malloc(request.authenticator.ciphertext.length))) {
179         retval = ENOMEM;
180         goto clean_scratch;
181     }
182
183 #define cleanup_encpart() {\
184 (void) memset(request.authenticator.ciphertext.data, 0,\
185              request.authenticator.ciphertext.length); \
186 free(request.authenticator.ciphertext.data); \
187 request.authenticator.ciphertext.length = 0; \
188 request.authenticator.ciphertext.data = 0;}
189
190     /* do any necessary key pre-processing */
191     if (retval = krb5_process_key(&eblock, &creds->keyblock)) {
192         goto clean_encpart;
193     }
194
195 #define cleanup_prockey() {(void) krb5_finish_key(&eblock);}
196
197     /* call the encryption routine */
198     if (retval = krb5_encrypt((krb5_pointer) scratch->data,
199                               (krb5_pointer) request.authenticator.ciphertext.data,
200                               scratch->length, &eblock, 0)) {
201         goto clean_prockey;
202     }
203
204     /* authenticator now assembled-- do some cleanup */
205     cleanup_scratch();
206
207     if (retval = krb5_finish_key(&eblock)) {
208         cleanup_encpart();
209         return retval;
210     }
211
212     if (!(retval = encode_krb5_ap_req(&request, &toutbuf))) {
213         *outbuf = *toutbuf;
214         xfree(toutbuf);
215     }
216     cleanup_ticket();
217     cleanup_encpart();
218     return retval;
219
220  clean_prockey:
221     cleanup_prockey();
222  clean_encpart:
223     cleanup_encpart();
224  clean_scratch:
225     cleanup_scratch();
226  clean_ticket:
227     cleanup_key();
228     cleanup_ticket();
229
230     return retval;
231 }
232
233 static krb5_error_code
234 generate_authenticator(authent, creds, cksum, key, seq_number)
235 krb5_authenticator *authent;
236 const krb5_creds *creds;
237 const krb5_checksum *cksum;
238 krb5_keyblock *key;
239 krb5_int32 seq_number;
240 {
241     authent->client = creds->client;
242     authent->checksum = (krb5_checksum *)cksum;
243     authent->subkey = key;
244     authent->seq_number = seq_number;
245
246     return(krb5_us_timeofday(&authent->ctime, &authent->cusec));
247 }