Move destest to builtin/des, because it depends on overriding some
[krb5.git] / src / kdc / pkinit_apple_server.c
1 /*
2  * Copyright (c) 2004-2008 Apple Inc.  All Rights Reserved.
3  *
4  * Export of this software from the United States of America may require
5  * a specific license from the United States Government.  It is the
6  * responsibility of any person or organization contemplating export to
7  * obtain such a license before exporting.
8  *
9  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
10  * distribute this software and its documentation for any purpose and
11  * without fee is hereby granted, provided that the above copyright
12  * notice appear in all copies and that both that copyright notice and
13  * this permission notice appear in supporting documentation, and that
14  * the name of Apple Inc. not be used in advertising or publicity pertaining
15  * to distribution of the software without specific, written prior
16  * permission.  Apple Inc. makes no representations about the suitability of
17  * this software for any purpose.  It is provided "as is" without express
18  * or implied warranty.
19  *
20  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
22  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23  *
24  */
25
26 /*
27  * pkinit_apple_server.c - Server side routines for PKINIT, Mac OS X version
28  *
29  * Created 21 May 2004 by Doug Mitchell at Apple.
30  */
31
32 #if APPLE_PKINIT
33
34 #include "pkinit_server.h"
35 #include "pkinit_asn1.h"
36 #include "pkinit_cms.h"
37 #include <assert.h>
38
39 #define     PKINIT_DEBUG    0
40 #if         PKINIT_DEBUG
41 #define     pkiDebug(args...)       printf(args)
42 #else
43 #define     pkiDebug(args...)
44 #endif
45
46 /*
47  * Parse PA-PK-AS-REQ message. Optionally evaluates the message's certificate chain. 
48  * Optionally returns various components. 
49  */
50 krb5_error_code krb5int_pkinit_as_req_parse(
51     krb5_context        context,
52     const krb5_data     *as_req,
53     krb5_timestamp      *kctime,        /* optionally RETURNED */
54     krb5_ui_4           *cusec,         /* microseconds, optionally RETURNED */
55     krb5_ui_4           *nonce,         /* optionally RETURNED */
56     krb5_checksum       *pa_cksum,      /* optional, contents mallocd and RETURNED */
57     krb5int_cert_sig_status *cert_status,/* optionally RETURNED */
58     krb5_ui_4           *num_cms_types, /* optionally RETURNED */
59     krb5int_algorithm_id **cms_types,   /* optionally mallocd and RETURNED */
60
61     /*
62      * Cert fields, all optionally RETURNED.
63      *
64      * signer_cert is the full X.509 leaf cert from the incoming SignedData.
65      * all_certs is an array of all of the certs in the incoming SignedData,
66      *    in full X.509 form. 
67      */
68     krb5_data           *signer_cert,   /* content mallocd */
69     krb5_ui_4           *num_all_certs, /* sizeof *all_certs */
70     krb5_data           **all_certs,    /* krb5_data's and their content mallocd */
71     
72     /*
73      * Array of trustedCertifiers, optionally RETURNED. These are DER-encoded 
74      * issuer/serial numbers. 
75      */
76     krb5_ui_4           *num_trusted_CAs,   /* sizeof *trusted_CAs */
77     krb5_data           **trusted_CAs,       /* krb5_data's and their content mallocd */
78     
79     /* KDC cert specified by client as kdcPkId. DER-encoded issuer/serial number. */
80     krb5_data           *kdc_cert)
81 {
82     krb5_error_code krtn;
83     krb5_data signed_auth_pack = {0, 0, NULL};
84     krb5_data raw_auth_pack = {0, 0, NULL};
85     krb5_data *raw_auth_pack_p = NULL;
86     krb5_boolean proceed = FALSE;
87     krb5_boolean need_auth_pack = FALSE;
88     krb5int_cms_content_type content_type;
89     krb5_pkinit_cert_db_t cert_db = NULL;
90     krb5_boolean is_signed;
91     krb5_boolean is_encrypted;
92    
93     assert(as_req != NULL);
94     
95     /* 
96      * We always have to decode the top-level AS-REQ...
97      */
98     krtn = krb5int_pkinit_pa_pk_as_req_decode(as_req, &signed_auth_pack,
99             num_trusted_CAs, trusted_CAs,           /* optional */
100             kdc_cert);                              /* optional */
101     if (krtn) {
102         pkiDebug("krb5int_pkinit_pa_pk_as_req_decode returned %d\n", (int)krtn);
103         return krtn;
104     }
105
106     /* Do we need info about or from the ContentInto or AuthPack? */
107     if ((kctime != NULL) || (cusec != NULL) || (nonce != NULL) || 
108         (pa_cksum != NULL) || (cms_types != NULL)) {
109         need_auth_pack = TRUE;
110         raw_auth_pack_p = &raw_auth_pack;
111     }
112     if (need_auth_pack || (cert_status != NULL) ||
113         (signer_cert != NULL) || (all_certs != NULL)) {
114         proceed = TRUE;
115     }
116     if (!proceed) {
117         krtn = 0;
118         goto err_out;
119     }
120     
121     /* Parse and possibly verify the ContentInfo */
122     krtn = krb5_pkinit_get_kdc_cert_db(&cert_db);
123     if (krtn) {
124         pkiDebug("pa_pk_as_req_parse: error in krb5_pkinit_get_kdc_cert_db\n");
125         goto err_out;
126     }
127     krtn = krb5int_pkinit_parse_cms_msg(&signed_auth_pack, cert_db, TRUE,
128         &is_signed, &is_encrypted,
129         raw_auth_pack_p, &content_type, signer_cert, cert_status, 
130         num_all_certs, all_certs);
131     if (krtn) {
132         pkiDebug("krb5int_pkinit_parse_content_info returned %d\n", (int)krtn);
133         goto err_out;
134     }
135
136     if (is_encrypted || !is_signed) {
137         pkiDebug("pkinit_parse_content_info: is_encrypted %s is_signed %s!\n",
138             is_encrypted ? "true" :"false",
139             is_signed ? "true" : "false");
140         krtn = KRB5KDC_ERR_PREAUTH_FAILED;
141         goto err_out;
142     }
143     if (content_type != ECT_PkAuthData) {
144         pkiDebug("authPack eContentType %d!\n", (int)content_type);
145         krtn = KRB5KDC_ERR_PREAUTH_FAILED;
146         goto err_out;
147     }
148     
149     /* optionally parse contents of authPack */
150     if (need_auth_pack) {
151         krtn = krb5int_pkinit_auth_pack_decode(&raw_auth_pack, kctime, 
152                                                cusec, nonce, pa_cksum, 
153                                                cms_types, num_cms_types);
154         if(krtn) {
155             pkiDebug("krb5int_pkinit_auth_pack_decode returned %d\n", (int)krtn);
156             goto err_out;
157         }
158     }
159
160 err_out:
161     /* free temp mallocd data that we didn't pass back to caller */
162     if(signed_auth_pack.data) {
163         free(signed_auth_pack.data);
164     }
165     if(raw_auth_pack.data) {
166         free(raw_auth_pack.data);
167     }
168     if(cert_db) {
169         krb5_pkinit_release_cert_db(cert_db);
170     }
171     return krtn;
172 }
173
174 /*
175  * Create a PA-PK-AS-REP message, public key (no Diffie Hellman) version.
176  *
177  * PA-PK-AS-REP is based on ReplyKeyPack like so:
178  *
179  * PA-PK-AS-REP ::= EnvelopedData(SignedData(ReplyKeyPack))
180  */
181 krb5_error_code krb5int_pkinit_as_rep_create(
182     krb5_context                context,
183     const krb5_keyblock         *key_block,
184     const krb5_checksum         *checksum,          /* checksum of corresponding AS-REQ */
185     krb5_pkinit_signing_cert_t  signer_cert,        /* server's cert */
186     krb5_boolean                include_server_cert,/* include signer_cert in SignerInfo */
187     const krb5_data             *recipient_cert,    /* client's cert */
188
189     /* 
190      * These correspond to the same out-parameters from 
191      * krb5int_pkinit_as_req_parse(). All are optional. 
192      */
193     krb5_ui_4                   num_cms_types,  
194     const krb5int_algorithm_id  *cms_types,     
195     krb5_ui_4                   num_trusted_CAs,
196     krb5_data                   *trusted_CAs,   
197     krb5_data                   *kdc_cert,
198     
199     krb5_data                   *as_rep)            /* mallocd and RETURNED */
200 {
201     krb5_data reply_key_pack = {0, 0, NULL};
202     krb5_error_code krtn;
203     krb5_data enc_key_pack = {0, 0, NULL};
204     
205     /* innermost content = ReplyKeyPack */
206     krtn = krb5int_pkinit_reply_key_pack_encode(key_block, checksum, 
207                                                 &reply_key_pack);
208     if (krtn) {
209         return krtn;
210     }
211     
212     /* 
213      * Put that in an EnvelopedData(SignedData)
214      * -- SignedData.EncapsulatedData.ContentType = id-pkinit-rkeyData
215      */
216     krtn = krb5int_pkinit_create_cms_msg(&reply_key_pack,
217         signer_cert,
218         recipient_cert,
219         ECT_PkReplyKeyKata,
220         num_cms_types, cms_types, 
221         &enc_key_pack);
222     if (krtn) {
223         goto err_out;
224     }
225     
226     /*
227      * Finally, wrap that inside of PA-PK-AS-REP
228      */
229     krtn = krb5int_pkinit_pa_pk_as_rep_encode(NULL, &enc_key_pack, as_rep);
230     
231 err_out:
232     if (reply_key_pack.data) {
233         free(reply_key_pack.data);
234     }
235     if (enc_key_pack.data) {
236         free(enc_key_pack.data);
237     }
238     return krtn;
239 }
240
241 #endif /* APPLE_PKINIT */