Imported Upstream version 1.10.2
[platform/upstream/krb5.git] / src / lib / krb5 / krb / pkinit_apple_utils.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * Copyright (c) 2004-2008 Apple Inc.  All Rights Reserved.
4  *
5  * Export of this software from the United States of America may require
6  * a specific license from the United States Government.  It is the
7  * responsibility of any person or organization contemplating export to
8  * obtain such a license before exporting.
9  *
10  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
11  * distribute this software and its documentation for any purpose and
12  * without fee is hereby granted, provided that the above copyright
13  * notice appear in all copies and that both that copyright notice and
14  * this permission notice appear in supporting documentation, and that
15  * the name of Apple Inc. not be used in advertising or publicity pertaining
16  * to distribution of the software without specific, written prior
17  * permission.  Apple Inc. makes no representations about the suitability of
18  * this software for any purpose.  It is provided "as is" without express
19  * or implied warranty.
20  *
21  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
23  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24  *
25  */
26
27 /*
28  * pkinit_apple_utils.c - PKINIT utilities, Mac OS X version
29  *
30  * Created 19 May 2004 by Doug Mitchell at Apple.
31  */
32
33 #if APPLE_PKINIT
34
35 #include "pkinit_apple_utils.h"
36 #include "pkinit_asn1.h"
37 #include <sys/errno.h>
38 #include <assert.h>
39 #include <string.h>
40 #include <time.h>
41 #include <stdio.h>
42 #include <ctype.h>
43 #include <Security/Security.h>
44
45 /*
46  * Cruft needed to attach to a module
47  */
48 static CSSM_VERSION vers = {2, 0};
49 static const CSSM_GUID testGuid = { 0xFADE, 0, 0, { 1,2,3,4,5,6,7,0 }};
50
51 /*
52  * Standard app-level memory functions required by CDSA.
53  */
54 static void * cuAppMalloc (CSSM_SIZE size, void *allocRef) {
55     return( malloc(size) );
56 }
57
58 static void cuAppFree (void *mem_ptr, void *allocRef) {
59     free(mem_ptr);
60     return;
61 }
62
63 static void * cuAppRealloc (void *ptr, CSSM_SIZE size, void *allocRef) {
64     return( realloc( ptr, size ) );
65 }
66
67 static void * cuAppCalloc (uint32 num, CSSM_SIZE size, void *allocRef) {
68     return( calloc( num, size ) );
69 }
70
71 static CSSM_API_MEMORY_FUNCS memFuncs = {
72     cuAppMalloc,
73     cuAppFree,
74     cuAppRealloc,
75     cuAppCalloc,
76     NULL
77 };
78
79 /*
80  * Init CSSM; returns CSSM_FALSE on error. Reusable.
81  */
82 static CSSM_BOOL cssmInitd = CSSM_FALSE;
83
84 static CSSM_BOOL cuCssmStartup()
85 {
86     CSSM_RETURN  crtn;
87     CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
88
89     if(cssmInitd) {
90         return CSSM_TRUE;
91     }
92     crtn = CSSM_Init (&vers,
93                       CSSM_PRIVILEGE_SCOPE_NONE,
94                       &testGuid,
95                       CSSM_KEY_HIERARCHY_NONE,
96                       &pvcPolicy,
97                       NULL /* reserved */);
98     if(crtn != CSSM_OK)
99     {
100         return CSSM_FALSE;
101     }
102     else {
103         cssmInitd = CSSM_TRUE;
104         return CSSM_TRUE;
105     }
106 }
107
108 CSSM_CL_HANDLE pkiClStartup(void)
109 {
110     CSSM_CL_HANDLE clHand;
111     CSSM_RETURN crtn;
112
113     if(cuCssmStartup() == CSSM_FALSE) {
114         return 0;
115     }
116     crtn = CSSM_ModuleLoad(&gGuidAppleX509CL,
117                            CSSM_KEY_HIERARCHY_NONE,
118                            NULL,                   /* eventHandler */
119                            NULL);                  /* AppNotifyCallbackCtx */
120     if(crtn) {
121         return 0;
122     }
123     crtn = CSSM_ModuleAttach (&gGuidAppleX509CL,
124                               &vers,
125                               &memFuncs,                  /* memFuncs */
126                               0,                          /* SubserviceID */
127                               CSSM_SERVICE_CL,            /* SubserviceFlags - Where is this used? */
128                               0,                          /* AttachFlags */
129                               CSSM_KEY_HIERARCHY_NONE,
130                               NULL,                       /* FunctionTable */
131                               0,                          /* NumFuncTable */
132                               NULL,                       /* reserved */
133                               &clHand);
134     if(crtn) {
135         return 0;
136     }
137     else {
138         return clHand;
139     }
140 }
141
142 CSSM_RETURN pkiClDetachUnload(
143     CSSM_CL_HANDLE  clHand)
144 {
145     CSSM_RETURN crtn = CSSM_ModuleDetach(clHand);
146     if(crtn) {
147         return crtn;
148     }
149     return CSSM_ModuleUnload(&gGuidAppleX509CL, NULL, NULL);
150 }
151
152 /*
153  * CSSM_DATA <--> krb5_ui_4
154  */
155 krb5_error_code pkiDataToInt(
156     const CSSM_DATA *cdata,
157     krb5_int32       *i)        /* RETURNED */
158 {
159     krb5_ui_4 len;
160     krb5_int32 rtn = 0;
161     krb5_ui_4 dex;
162     uint8 *cp = NULL;
163
164     if((cdata->Length == 0) || (cdata->Data == NULL)) {
165         *i = 0;
166         return 0;
167     }
168     len = cdata->Length;
169     if(len > sizeof(krb5_int32)) {
170         return ASN1_BAD_LENGTH;
171     }
172
173     cp = cdata->Data;
174     for(dex=0; dex<len; dex++) {
175         rtn = (rtn << 8) | *cp++;
176     }
177     *i = rtn;
178     return 0;
179 }
180
181 krb5_error_code pkiIntToData(
182     krb5_int32      num,
183     CSSM_DATA       *cdata,
184     SecAsn1CoderRef coder)
185 {
186     krb5_ui_4 unum = (krb5_ui_4)num;
187     uint32 len = 0;
188     uint8 *cp = NULL;
189     unsigned i;
190
191     if(unum < 0x100) {
192         len = 1;
193     }
194     else if(unum < 0x10000) {
195         len = 2;
196     }
197     else if(unum < 0x1000000) {
198         len = 3;
199     }
200     else {
201         len = 4;
202     }
203     if(SecAsn1AllocItem(coder, cdata, len)) {
204         return ENOMEM;
205     }
206     cp = &cdata->Data[len - 1];
207     for(i=0; i<len; i++) {
208         *cp-- = unum & 0xff;
209         unum >>= 8;
210     }
211     return 0;
212 }
213
214 /*
215  * raw data --> krb5_data
216  */
217 krb5_error_code pkiDataToKrb5Data(
218     const void *data,
219     unsigned dataLen,
220     krb5_data *kd)
221 {
222     assert(data != NULL);
223     assert(kd != NULL);
224     kd->data = (char *)malloc(dataLen);
225     if(kd->data == NULL) {
226         return ENOMEM;
227     }
228     kd->length = dataLen;
229     memmove(kd->data, data, dataLen);
230     return 0;
231 }
232
233 /*
234  * CSSM_DATA <--> krb5_data
235  *
236  * CSSM_DATA data is managed by a SecAsn1CoderRef; krb5_data data is mallocd.
237  *
238  * Both return nonzero on error.
239  */
240 krb5_error_code pkiCssmDataToKrb5Data(
241     const CSSM_DATA *cd,
242     krb5_data *kd)
243 {
244     assert(cd != NULL);
245     return pkiDataToKrb5Data(cd->Data, cd->Length, kd);
246 }
247
248 krb5_error_code pkiKrb5DataToCssm(
249     const krb5_data *kd,
250     CSSM_DATA       *cd,
251     SecAsn1CoderRef coder)
252 {
253     assert((cd != NULL) && (kd != NULL));
254     if(SecAsn1AllocCopy(coder, kd->data, kd->length, cd)) {
255         return ENOMEM;
256     }
257     return 0;
258 }
259
260 /*
261  * CFDataRef --> krb5_data, mallocing the destination contents.
262  */
263 krb5_error_code pkiCfDataToKrb5Data(
264     CFDataRef       cfData,
265     krb5_data       *kd)        /* content mallocd and RETURNED */
266 {
267     return pkiDataToKrb5Data(CFDataGetBytePtr(cfData),
268                              CFDataGetLength(cfData), kd);
269 }
270
271 krb5_boolean pkiCompareCssmData(
272     const CSSM_DATA *d1,
273     const CSSM_DATA *d2)
274 {
275     if((d1 == NULL) || (d2 == NULL)) {
276         return FALSE;
277     }
278     if(d1->Length != d2->Length) {
279         return FALSE;
280     }
281     if(memcmp(d1->Data, d2->Data, d1->Length)) {
282         return FALSE;
283     }
284     else {
285         return TRUE;
286     }
287 }
288
289 /*
290  * krb5_timestamp --> a mallocd string in generalized format
291  */
292 krb5_error_code pkiKrbTimestampToStr(
293     krb5_timestamp kts,
294     char **str)             /* mallocd and RETURNED */
295 {
296     char *outStr = NULL;
297     time_t gmt_time = kts;
298     struct tm *utc = gmtime(&gmt_time);
299     if (utc == NULL ||
300         utc->tm_year > 8099 || utc->tm_mon > 11 ||
301         utc->tm_mday > 31 || utc->tm_hour > 23 ||
302         utc->tm_min > 59 || utc->tm_sec > 59) {
303         return ASN1_BAD_GMTIME;
304     }
305     if (asprintf(&outStr, "%04d%02d%02d%02d%02d%02dZ",
306                  utc->tm_year + 1900, utc->tm_mon + 1,
307                  utc->tm_mday, utc->tm_hour, utc->tm_min, utc->tm_sec) < 0) {
308         return ENOMEM;
309     }
310     *str = outStr;
311     return 0;
312 }
313
314 krb5_error_code pkiTimeStrToKrbTimestamp(
315     const char          *str,
316     unsigned            len,
317     krb5_timestamp      *kts)       /* RETURNED */
318 {
319     char        szTemp[5];
320     unsigned    x;
321     unsigned    i;
322     char        *cp;
323     struct tm   tmp;
324     time_t      t;
325
326     if(len != 15) {
327         return ASN1_BAD_LENGTH;
328     }
329
330     if((str == NULL) || (kts == NULL)) {
331         return KRB5_CRYPTO_INTERNAL;
332     }
333
334     cp = (char *)str;
335     memset(&tmp, 0, sizeof(tmp));
336
337     /* check that all characters except last are digits */
338     for(i=0; i<(len - 1); i++) {
339         if ( !(isdigit(cp[i])) ) {
340             return ASN1_BAD_TIMEFORMAT;
341         }
342     }
343
344     /* check last character is a 'Z' */
345     if(cp[len - 1] != 'Z' )     {
346         return ASN1_BAD_TIMEFORMAT;
347     }
348
349     /* YEAR */
350     szTemp[0] = *cp++;
351     szTemp[1] = *cp++;
352     szTemp[2] = *cp++;
353     szTemp[3] = *cp++;
354     szTemp[4] = '\0';
355     x = atoi( szTemp );
356     /* by definition - tm_year is year - 1900 */
357     tmp.tm_year = x - 1900;
358
359     /* MONTH */
360     szTemp[0] = *cp++;
361     szTemp[1] = *cp++;
362     szTemp[2] = '\0';
363     x = atoi( szTemp );
364     /* in the string, months are from 1 to 12 */
365     if((x > 12) || (x <= 0)) {
366         return ASN1_BAD_TIMEFORMAT;
367     }
368     /* in a tm, 0 to 11 */
369     tmp.tm_mon = x - 1;
370
371     /* DAY */
372     szTemp[0] = *cp++;
373     szTemp[1] = *cp++;
374     szTemp[2] = '\0';
375     x = atoi( szTemp );
376     /* 1..31 */
377     if((x > 31) || (x <= 0)) {
378         return ASN1_BAD_TIMEFORMAT;
379     }
380     tmp.tm_mday = x;
381
382     /* HOUR */
383     szTemp[0] = *cp++;
384     szTemp[1] = *cp++;
385     szTemp[2] = '\0';
386     x = atoi( szTemp );
387     if((x > 23) || (x < 0)) {
388         return ASN1_BAD_TIMEFORMAT;
389     }
390     tmp.tm_hour = x;
391
392     /* MINUTE */
393     szTemp[0] = *cp++;
394     szTemp[1] = *cp++;
395     szTemp[2] = '\0';
396     x = atoi( szTemp );
397     if((x > 59) || (x < 0)) {
398         return ASN1_BAD_TIMEFORMAT;
399     }
400     tmp.tm_min = x;
401
402     /* SECOND */
403     szTemp[0] = *cp++;
404     szTemp[1] = *cp++;
405     szTemp[2] = '\0';
406     x = atoi( szTemp );
407     if((x > 59) || (x < 0)) {
408         return ASN1_BAD_TIMEFORMAT;
409     }
410     tmp.tm_sec = x;
411     t = timegm(&tmp);
412     if(t == -1) {
413         return ASN1_BAD_TIMEFORMAT;
414     }
415     *kts = t;
416     return 0;
417 }
418
419 /*
420  * How many items in a NULL-terminated array of pointers?
421  */
422 unsigned pkiNssArraySize(
423     const void **array)
424 {
425     unsigned count = 0;
426     if (array) {
427         while (*array++) {
428             count++;
429         }
430     }
431     return count;
432 }
433
434 #endif /* APPLE_PKINIT */