2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
22 Created 10/9/2000 by Doug Mitchell.
25 #include <Security/cssmtype.h>
26 #include <Security/cssmapi.h>
27 #include <Security/x509defs.h>
28 #include <Security/oidscert.h>
29 #include <Security/oidsalg.h>
30 #include <Security/cssmapple.h>
32 #include "certGroupUtils.h"
33 #include "tpdebugging.h"
36 #include <string.h> /* for memcmp */
40 * Copy one CSSM_DATA to another, mallocing destination.
47 dst
->Data
= (uint8
*)alloc
.malloc(src
->Length
);
48 dst
->Length
= src
->Length
;
49 memmove(dst
->Data
, src
->Data
, src
->Length
);
53 * Malloc a CSSM_DATA, copy another one to it.
55 CSSM_DATA_PTR
tpMallocCopyCssmData(
59 CSSM_DATA_PTR dst
= (CSSM_DATA_PTR
)alloc
.malloc(sizeof(CSSM_DATA
));
60 tpCopyCssmData(alloc
, src
, dst
);
65 * Free the data referenced by a CSSM data, and optionally, the struct itself.
75 if(data
->Length
!= 0) {
76 tpFree(alloc
, data
->Data
);
88 * Compare two CSSM_DATAs, return CSSM_TRUE if identical.
90 CSSM_BOOL
tpCompareCssmData(
91 const CSSM_DATA
*data1
,
92 const CSSM_DATA
*data2
)
94 if((data1
== NULL
) || (data1
->Data
== NULL
) ||
95 (data2
== NULL
) || (data2
->Data
== NULL
) ||
96 (data1
->Length
!= data2
->Length
)) {
99 if(data1
->Length
!= data2
->Length
) {
102 if(memcmp(data1
->Data
, data2
->Data
, data1
->Length
) == 0) {
111 * Free memory via specified plugin's app-level allocator
113 void tpFreePluginMemory(
117 CSSM_API_MEMORY_FUNCS memFuncs
;
118 CSSM_RETURN crtn
= CSSM_GetAPIMemoryFunctions(hand
, &memFuncs
);
120 tpErrorLog("CSSM_GetAPIMemoryFunctions failure\n");
121 /* oh well, leak and continue */
124 memFuncs
.free_func(p
, memFuncs
.AllocRef
);
128 * Obtain the public key blob from a cert.
130 CSSM_DATA_PTR
tp_CertGetPublicKey(
132 CSSM_DATA_PTR
*valueToFree
) // used in tp_CertFreePublicKey
136 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*keyInfo
;
139 crtn
= cert
->fetchField(&CSSMOID_X509V1SubjectPublicKeyCStruct
, &val
);
141 tpErrorLog("Error on CSSM_CL_CertGetFirstFieldValue(PublicKeyCStruct)\n");
145 keyInfo
= (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*)val
->Data
;
146 return &keyInfo
->subjectPublicKey
;
149 void tp_CertFreePublicKey(
150 CSSM_CL_HANDLE clHand
,
153 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_X509V1SubjectPublicKeyCStruct
, value
);
157 * Obtain signature algorithm info from a cert.
159 CSSM_X509_ALGORITHM_IDENTIFIER_PTR
tp_CertGetAlgId(
161 CSSM_DATA_PTR
*valueToFree
) // used in tp_CertFreeAlgId
167 crtn
= cert
->fetchField(&CSSMOID_X509V1SignatureAlgorithm
, &val
);
169 tpErrorLog("Error on fetchField(CSSMOID_X509V1SignatureAlgorithm)\n");
173 return (CSSM_X509_ALGORITHM_IDENTIFIER_PTR
)val
->Data
;
176 void tp_CertFreeAlgId(
177 CSSM_CL_HANDLE clHand
,
180 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_X509V1SignatureAlgorithm
, value
);
184 * Determine if two certs - passed in encoded form - are equivalent.
186 CSSM_BOOL
tp_CompareCerts(
187 const CSSM_DATA
*cert1
,
188 const CSSM_DATA
*cert2
)
190 return tpCompareCssmData(cert1
, cert2
);
195 * Given a aignature OID, return the corresponding CSSM_ALGID for the
196 * signature the required key.
198 CSSM_ALGORITHMS
tpOidToAldId(
200 CSSM_ALGORITHMS
*keyAlg
) // RETURNED
202 *keyAlg
= CSSM_ALGID_RSA
; // default
203 if(tpCompareOids(oid
, &CSSMOID_MD2WithRSA
)) {
204 return CSSM_ALGID_MD2WithRSA
;
206 else if(tpCompareOids(oid
, &CSSMOID_MD5WithRSA
)) {
207 return CSSM_ALGID_MD5WithRSA
;
209 else if(tpCompareOids(oid
, &CSSMOID_SHA1WithRSA
)) {
210 return CSSM_ALGID_SHA1WithRSA
;
212 else if(tpCompareOids(oid
, &CSSMOID_SHA1WithRSA_OIW
)) {
213 return CSSM_ALGID_SHA1WithRSA
;
215 else if(tpCompareOids(oid
, &CSSMOID_SHA1WithDSA
)) {
216 *keyAlg
= CSSM_ALGID_DSA
;
217 return CSSM_ALGID_SHA1WithDSA
;
219 else if(tpCompareOids(oid
, &CSSMOID_APPLE_FEE_MD5
)) {
220 *keyAlg
= CSSM_ALGID_FEE
;
221 return CSSM_ALGID_FEE_MD5
;
223 else if(tpCompareOids(oid
, &CSSMOID_APPLE_FEE_SHA1
)) {
224 *keyAlg
= CSSM_ALGID_FEE
;
225 return CSSM_ALGID_FEE_SHA1
;
227 else if(tpCompareOids(oid
, &CSSMOID_APPLE_ECDSA
)) {
228 *keyAlg
= CSSM_ALGID_FEE
;
229 return CSSM_ALGID_SHA1WithECDSA
;
232 *keyAlg
= CSSM_ALGID_NONE
;
233 return CSSM_ALGID_NONE
;
238 * Convert a C string to lower case in place. NULL terminator not needed.
244 for(unsigned i
=0; i
<strLen
; i
++) {
245 *str
= tolower(*str
);
251 * Normalize an RFC822 addr-spec. This consists of converting
252 * all characters following the '@' character to lower case.
254 void tpNormalizeAddrSpec(
258 while((*addr
!= '@') && (addrLen
!= 0)) {
263 tpPolicyError("tpNormalizeAddrSpec: bad addr-spec");
266 tpToLower(addr
, addrLen
);
270 *** dnsName compare support.
271 *** Please do not make any changes to this code without talking to
272 *** dmitch about updating (if necessary) and running (always)
273 *** regression tests which specifically test this logic.
277 * Max length of a distinguished name component (label) we handle.
278 * Various RFCs spec this out at 63 bytes; we're just allocating space
279 * for these on the stack, so why not cut some slack.
281 #define MAX_DNS_COMP_LEN 128
284 * Obtain the next component from a DNS Name.
285 * Caller mallocs outBuf, size >= MAX_DNS_COMP_LEN.
286 * Returns true if a component was found.
288 static bool tpNextDnsComp(
290 uint32
&inBufLen
, // IN/OUT
291 char *outBuf
, // component RETURNED here
292 uint32
&outBufLen
) // RETURNED length of component
299 /* skip over leading '.' */
302 if(--inBufLen
== 0) {
307 /* copy chars until out of data or next '.' found */
312 *outBuf
++ = *inBuf
++;
315 if(outBufLen
>= MAX_DNS_COMP_LEN
) {
319 } while(inBufLen
!= 0);
329 * Find location of specified substring in given bigstring. Returns
330 * pointer to start of substring in bigstring, else returns NULL.
332 static const char *tpSubStr(
338 /* stop searching substrLen chars before end of bigstr */
339 const char *endBigStr
= bigstr
+ bigstrLen
- substrLen
;
340 for( ; bigstr
<= endBigStr
; ) {
341 if(*bigstr
== *substr
) {
342 /* first char match - remainder? */
344 /* don't count on memcmp(a,b,0) */
347 if(!memcmp(bigstr
+1, substr
+1, substrLen
- 1)) {
357 * Compare two DNS components, with full wildcard check. We assume
358 * that no '.' chars exist (per the processing performed in
359 * tpNextDnsComp()). Returns CSSM_TRUE on match, else CSSM_FALSE.
361 static CSSM_BOOL
tpCompareComps(
362 const char *hostComp
, // no wildcards
364 const char *certComp
, // wildcards OK here
367 const char *endCertComp
= certComp
+ certCompLen
;
368 const char *endHostComp
= hostComp
+ hostCompLen
;
370 /* wild card in cert name? */
371 const char *wildCard
= tpSubStr(certComp
, certCompLen
,
373 if(wildCard
== NULL
) {
374 /* no, require perfect literal match right now */
375 if((hostCompLen
== certCompLen
) &&
376 !memcmp(hostComp
, certComp
, certCompLen
)) {
384 if(wildCard
!= certComp
) {
386 * Require literal match of hostComp with certComp
387 * up until (but not including) the wildcard
389 uint32 subStrLen
= wildCard
- certComp
;
390 if(subStrLen
> hostCompLen
) {
391 /* out of host name chars */
394 if(memcmp(certComp
, hostComp
, subStrLen
)) {
397 /* OK, skip over substring */
398 hostComp
+= subStrLen
;
399 hostCompLen
-= subStrLen
;
400 /* start parsing at the wildcard itself */
402 certCompLen
-= subStrLen
;
407 * Currently looking at a wildcard.
409 * Find substring in hostComp which matches from the char after
410 * the wildcard up to whichever of these comes next:
413 * -- another wildcard
416 if(wildCard
== endCertComp
) {
418 * -- Wild card at end of cert's DNS
419 * -- nothing else to match - rest of hostComp is the wildcard
426 const char *afterSubStr
; // in certComp
427 afterSubStr
= tpSubStr(wildCard
, endCertComp
- wildCard
,
429 if(afterSubStr
== NULL
) {
430 /* no more wildcards - use end of certComp */
431 afterSubStr
= endCertComp
;
433 uint32 subStrLen
= afterSubStr
- wildCard
;
434 const char *foundSub
= tpSubStr(hostComp
, hostCompLen
,
435 wildCard
, subStrLen
);
436 if(foundSub
== NULL
) {
437 /* No match of explicit chars */
441 /* found it - skip past this substring */
442 hostComp
= foundSub
+ subStrLen
;
443 hostCompLen
= endHostComp
- hostComp
;
444 certComp
= afterSubStr
;
445 certCompLen
= endCertComp
- afterSubStr
;
447 } while((hostCompLen
!= 0) || (certCompLen
!= 0));
448 if((hostCompLen
== 0) && (certCompLen
== 0)) {
452 /* end of one but not the other */
458 * Compare hostname, is presented to the TP in
459 * CSSM_APPLE_TP_SSL_OPTIONS.ServerName, to a server name obtained
460 * from the server's cert (i.e., from subjectAltName or commonName).
461 * Limited wildcard checking is performed here.
463 * The incoming hostname is assumed to have been processed by tpToLower();
464 * we'll perform that processing on certName here.
466 * Returns CSSM_TRUE on match, else CSSM_FALSE.
468 CSSM_BOOL
tpCompareHostNames(
469 const char *hostName
, // spec'd by app, tpToLower'd
471 char *certName
, // from cert, we tpToLower
474 tpToLower(certName
, certNameLen
);
476 /* tolerate optional NULL terminators for both */
477 if(hostName
[hostNameLen
- 1] == '\0') {
480 if(certName
[certNameLen
- 1] == '\0') {
484 /* case 1: exact match */
485 if((certNameLen
== hostNameLen
) &&
486 !memcmp(certName
, hostName
, certNameLen
)) {
491 * Case 2: Compare one component at a time, handling wildcards in
492 * cert's server name. The characters implicitly matched by a
493 * wildcard span only one component of a dnsName.
496 /* get next component from each dnsName */
497 char hostComp
[MAX_DNS_COMP_LEN
];
498 char certComp
[MAX_DNS_COMP_LEN
];
502 bool foundHost
= tpNextDnsComp(hostName
, hostNameLen
,
503 hostComp
, hostCompLen
);
504 bool foundCert
= tpNextDnsComp(certName
, certNameLen
,
505 certComp
, certCompLen
);
506 if(foundHost
!= foundCert
) {
507 /* unequal number of components */
508 tpPolicyError("tpCompareHostNames: wildcard mismatch (1)");
512 /* normal successful termination */
516 /* compare individual components */
517 if(!tpCompareComps(hostComp
, hostCompLen
,
518 certComp
, certCompLen
)) {
519 tpPolicyError("tpCompareHostNames: wildcard mismatch (2)");
523 /* skip over this component */
524 hostName
+= hostCompLen
;
525 certName
+= certCompLen
;
533 * Compare email address, is presented to the TP in
534 * CSSM_APPLE_TP_SMIME_OPTIONS.SenderEmail, to a string obtained
535 * from the sender's cert (i.e., from subjectAltName or Subject DN).
537 * Returns CSSM_TRUE on match, else CSSM_FALSE.
539 * Incomiong appEmail string has already been tpNormalizeAddrSpec'd.
540 * We do that for certEmail string here.
542 CSSM_BOOL
tpCompareEmailAddr(
543 const char *appEmail
, // spec'd by app, normalized
545 char *certEmail
, // from cert, we normalize
548 tpNormalizeAddrSpec(certEmail
, certEmailLen
);
550 /* tolerate optional NULL terminators for both */
551 if(appEmail
[appEmailLen
- 1] == '\0') {
554 if(certEmail
[certEmailLen
- 1] == '\0') {
557 if((certEmailLen
== appEmailLen
) &&
558 !memcmp(certEmail
, appEmail
, certEmailLen
)) {
563 tpPolicyError("tpCompareEmailAddr: app/cert email addrs mismatch");