]> git.saurik.com Git - apple/security.git/blob - sec/Security/SecSCEP.c
Security-55471.14.8.tar.gz
[apple/security.git] / sec / Security / SecSCEP.c
1 /*
2 * Copyright (c) 2008-2010 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include "SecSCEP.h"
25
26 #include <Security/SecCMS.h>
27 #include <Security/SecRandom.h>
28 #include <Security/SecIdentityPriv.h>
29 #include <string.h>
30 #include <AssertMacros.h>
31 #include <CommonCrypto/CommonDigest.h>
32 #include <CommonCrypto/CommonDigestSPI.h>
33 #include <Security/SecItem.h>
34 #include <Security/SecInternal.h>
35 #include <Security/SecCertificateInternal.h>
36 #include <Security/SecKeyPriv.h>
37 #include <Security/SecInternal.h>
38 #include <libDER/DER_Encode.h>
39 #include <uuid/uuid.h>
40 #include <utilities/array_size.h>
41 #include <utilities/debugging.h>
42 #include <utilities/SecIOFormat.h>
43
44 typedef enum {
45 messageType = 2,
46 pkiStatus = 3,
47 failInfo = 4,
48 senderNonce = 5,
49 recipientNonce = 6,
50 transId = 7
51 } scep_attr_t;
52
53 static CFDataRef scep_oid(scep_attr_t type)
54 {
55 /* +-------------------+-----------------------------------------------+
56 | Name | ASN.1 Definition |
57 +-------------------+-----------------------------------------------+
58 | id-VeriSign | OBJECT_IDENTIFIER ::= {2 16 US(840) 1 |
59 | | VeriSign(113733)} |
60 | id-pki | OBJECT_IDENTIFIER ::= {id-VeriSign pki(1)} |
61 | id-attributes | OBJECT_IDENTIFIER ::= {id-pki attributes(9)} |
62 | id-messageType | OBJECT_IDENTIFIER ::= {id-attributes |
63 | | messageType(2)} |
64 | id-pkiStatus | OBJECT_IDENTIFIER ::= {id-attributes |
65 | | pkiStatus(3)} |
66 | id-failInfo | OBJECT_IDENTIFIER ::= {id-attributes |
67 | | failInfo(4)} |
68 | id-senderNonce | OBJECT_IDENTIFIER ::= {id-attributes |
69 | | senderNonce(5)} |
70 | id-recipientNonce | OBJECT_IDENTIFIER ::= {id-attributes |
71 | | recipientNonce(6)} |
72 | id-transId | OBJECT_IDENTIFIER ::= {id-attributes |
73 | | transId(7)} |
74 | id-extensionReq | OBJECT_IDENTIFIER ::= {id-attributes |
75 | | extensionReq(8)} |
76 +-------------------+-----------------------------------------------+ */
77 uint8_t oid_scep_attrs[] =
78 { 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0 };
79 /* messageType:2 pkiStatus:3 failInfo:4 senderNonce:5 recipientNonce:6 transId:7 */
80 if ((type < messageType) || (type > transId))
81 return NULL;
82
83 oid_scep_attrs[sizeof(oid_scep_attrs) - 1] = type;
84 return CFDataCreate(kCFAllocatorDefault, oid_scep_attrs, sizeof(oid_scep_attrs));
85 }
86
87 static const char CertRep[] = "3";
88 static const char PKCSReq[] = "19";
89 static const char GetCertInitial[] = "20";
90 static const char GetCert[] = "21";
91 static const char GetCRL[] = "22";
92 static const char PKIStatusSUCCESS[] = "0";
93 static const char PKIStatusFAILURE[] = "2";
94 static const char PKIStatusPENDING[] = "3";
95
96 static CFDataRef
97 printable_string_data(size_t length, const char *bytes)
98 {
99 DERSize der_length_len = DERLengthOfLength(length);
100 size_t value_length = sizeof(SecASN1PrintableString) + der_length_len + length;
101 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, value_length);
102 CFDataSetLength(data, value_length);
103 uint8_t *ptr = (uint8_t *)CFDataGetBytePtr(data);
104 *ptr++ = SecASN1PrintableString;
105 DEREncodeLength(length, ptr, &der_length_len);
106 ptr += der_length_len;
107 memcpy(ptr, bytes, length);
108 return (CFDataRef)data;
109 }
110
111 #define scep_result(value) printable_string_data(sizeof(value)-1, value)
112
113 static CFTypeRef
114 dictionary_array_value_1(CFDictionaryRef attrs, CFTypeRef attr)
115 {
116 CFTypeRef value = NULL;
117 CFArrayRef attr_values = NULL;
118
119 require(attr_values = (CFArrayRef)CFDictionaryGetValue(attrs, attr), out);
120 require(CFArrayGetCount(attr_values) == 1, out);
121 value = CFArrayGetValueAtIndex(attr_values, 0);
122 out:
123 return value;
124 }
125
126 /* @@@ consider splitting into function returning single value
127 and function creating printable string from c str */
128 static bool scep_attr_has_val(CFDictionaryRef attrs, scep_attr_t attr, const char *val)
129 {
130 bool result = false;
131 CFDataRef msgtype_value_data = printable_string_data(strlen(val), val);
132 CFArrayRef msgtype_value_datas = CFArrayCreate(kCFAllocatorDefault,
133 (const void **)&msgtype_value_data, 1, &kCFTypeArrayCallBacks);
134 CFRelease(msgtype_value_data);
135 CFDataRef msgtype_oid_data = scep_oid(attr);
136 CFArrayRef msgtype_values = (CFArrayRef)CFDictionaryGetValue(attrs, msgtype_oid_data);
137 CFRelease(msgtype_oid_data);
138 if (msgtype_values && CFEqual(msgtype_value_datas, msgtype_values))
139 result = true;
140 CFRelease(msgtype_value_datas);
141
142 return result;
143 }
144
145 static CFDataRef hexencode(CFDataRef data)
146 {
147 CFIndex ix, length = CFDataGetLength(data);
148 const uint8_t *bin_data = CFDataGetBytePtr(data);
149 uint8_t *hex_data = calloc(1, 2*length + 1);
150 require(length && bin_data && hex_data, out);
151
152 for (ix = 0; ix < length; ix++)
153 snprintf((char *)&hex_data[2*ix], 3, "%02X", bin_data[ix]);
154
155 return CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, hex_data,
156 2*length, kCFAllocatorMalloc);
157 out:
158 if (hex_data)
159 free(hex_data);
160 return NULL;
161 }
162
163 static CFDataRef pubkeyhash(SecKeyRef key)
164 {
165 CFTypeRef key_type = NULL;
166 CFDictionaryRef pubkey_attrs = NULL;
167 CFDataRef hash_pubkey_data = NULL, pubkey_data = NULL;
168 uint8_t pubkey_hash[CC_SHA1_DIGEST_LENGTH];
169
170 require(pubkey_attrs = SecKeyCopyAttributeDictionary(key), out);
171 require( (key_type = CFDictionaryGetValue(pubkey_attrs, kSecAttrKeyClass)) &&
172 CFEqual(key_type, kSecAttrKeyClassPublic), out);
173 require(pubkey_data = CFDictionaryGetValue(pubkey_attrs, kSecValueData), out);
174 require((unsigned long)CFDataGetLength(pubkey_data)<=UINT32_MAX, out); /* Correct as long as CFIndex is long */
175 CCDigest(kCCDigestSHA1, CFDataGetBytePtr(pubkey_data), (CC_LONG)CFDataGetLength(pubkey_data), pubkey_hash);
176 hash_pubkey_data = CFDataCreate(kCFAllocatorDefault, pubkey_hash, sizeof(pubkey_hash));
177 out:
178 CFReleaseSafe(pubkey_attrs);
179 return hash_pubkey_data;
180 }
181
182 static void generate_sender_nonce(CFMutableDictionaryRef dict)
183 {
184 /* random sender nonce, to be verified against recipient nonce in reply */
185 CFDataRef senderNonce_oid_data = scep_oid(senderNonce);
186 uint8_t senderNonce_value[18] = { 4, 16, };
187 SecRandomCopyBytes(kSecRandomDefault, sizeof(senderNonce_value) - 2, senderNonce_value + 2);
188 CFDataRef senderNonce_value_data = CFDataCreate(kCFAllocatorDefault,
189 senderNonce_value, sizeof(senderNonce_value));
190 if (senderNonce_oid_data && senderNonce_value_data)
191 CFDictionarySetValue(dict, senderNonce_oid_data, senderNonce_value_data);
192 CFReleaseNull(senderNonce_oid_data);
193 CFReleaseNull(senderNonce_value_data);
194 }
195
196 SecIdentityRef SecSCEPCreateTemporaryIdentity(SecKeyRef publicKey, SecKeyRef privateKey)
197 {
198 int key_usage = kSecKeyUsageDigitalSignature | kSecKeyUsageKeyEncipherment;
199 CFDictionaryRef self_signed_parameters = NULL;
200 CFNumberRef key_usage_num = NULL;
201 SecCertificateRef self_signed_certificate = NULL;
202 SecIdentityRef self_signed_identity = NULL;
203 CFStringRef cn_uuid = NULL;
204 CFArrayRef cn_dn = NULL, cn_dns = NULL, unique_rdns = NULL;
205
206 key_usage_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &key_usage);
207 require(key_usage_num, out);
208
209 const void *key[] = { kSecCertificateKeyUsage };
210 const void *val[] = { key_usage_num };
211 self_signed_parameters = CFDictionaryCreate(kCFAllocatorDefault,
212 key, val, array_size(key),
213 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
214 require(self_signed_parameters, out);
215
216 char uuid_string[37] = {};
217 uuid_t uuid;
218 uuid_generate_random(uuid);
219 uuid_unparse(uuid, uuid_string);
220 cn_uuid = CFStringCreateWithCString(kCFAllocatorDefault, uuid_string, kCFStringEncodingASCII);
221 require(cn_uuid, out);
222 const void * cn[] = { kSecOidCommonName, cn_uuid };
223 cn_dn = CFArrayCreate(kCFAllocatorDefault, cn, 2, NULL);
224 require(cn_dn, out);
225 cn_dns = CFArrayCreate(kCFAllocatorDefault, (const void **)&cn_dn, 1, NULL);
226 require(cn_dns, out);
227 unique_rdns = CFArrayCreate(kCFAllocatorDefault, (const void **)&cn_dns, 1, NULL);
228 require(unique_rdns, out);
229
230 self_signed_certificate = SecGenerateSelfSignedCertificate(unique_rdns, self_signed_parameters, publicKey, privateKey);
231 require(self_signed_certificate, out);
232 self_signed_identity = SecIdentityCreate(kCFAllocatorDefault, self_signed_certificate, privateKey);
233
234 out:
235 CFReleaseSafe(key_usage_num);
236 CFReleaseSafe(self_signed_parameters);
237 CFReleaseSafe(self_signed_certificate);
238 CFReleaseSafe(unique_rdns);
239 CFReleaseSafe(cn_dns);
240 CFReleaseSafe(cn_dn);
241 CFReleaseSafe(cn_uuid);
242
243 return self_signed_identity;
244 }
245
246 CFDataRef
247 SecSCEPGenerateCertificateRequest(CFArrayRef subject, CFDictionaryRef parameters,
248 SecKeyRef publicKey, SecKeyRef privateKey,
249 SecIdentityRef signer, CFTypeRef recipients)
250 {
251 CFDataRef csr = NULL;
252 CFMutableDataRef enveloped_data = NULL;
253 CFMutableDictionaryRef simple_attr = NULL;
254 SecIdentityRef self_signed_identity = NULL;
255 CFMutableDataRef signed_request = NULL;
256 SecCertificateRef recipient = NULL;
257
258 if (CFGetTypeID(recipients) == SecCertificateGetTypeID()) {
259 recipient = (SecCertificateRef)recipients;
260 } else if (CFGetTypeID(recipients) == CFArrayGetTypeID()) {
261 CFIndex recipient_count = CFArrayGetCount(recipients);
262 if (recipient_count > 1) {
263 /* get the encryption cert */
264 recipient = (SecCertificateRef)CFArrayGetValueAtIndex(recipients, 0);
265 } else if (recipient_count == 1) {
266 /* if there is at least one we'll assume it's sign+encrypt */
267 recipient = (SecCertificateRef)CFArrayGetValueAtIndex(recipients, 0);
268 }
269 }
270 require(recipient, out);
271
272 require(csr = SecGenerateCertificateRequest(subject, parameters, publicKey, privateKey), out);
273 require(enveloped_data = CFDataCreateMutable(kCFAllocatorDefault, 0), out);
274 require_noerr(SecCMSCreateEnvelopedData(recipient, parameters, csr, enveloped_data), out);
275 CFReleaseNull(csr);
276
277 simple_attr = CFDictionaryCreateMutable(kCFAllocatorDefault, 3,
278 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
279
280 /* generate a transaction id: hex encoded pubkey hash */
281 CFDataRef public_key_hash = pubkeyhash(publicKey);
282 CFDataRef public_key_hash_hex = hexencode(public_key_hash);
283 CFReleaseSafe(public_key_hash);
284 CFDataRef transid_oid_data = scep_oid(transId);
285 CFDataRef transid_data = printable_string_data(CFDataGetLength(public_key_hash_hex),
286 (const char *)CFDataGetBytePtr(public_key_hash_hex));
287 CFReleaseSafe(public_key_hash_hex);
288
289 CFDictionarySetValue(simple_attr, transid_oid_data, transid_data);
290 CFReleaseNull(transid_oid_data);
291 CFReleaseNull(transid_data);
292
293 /* message type: PKCSReq (19) */
294 CFDataRef msgtype_value_data = NULL;
295 CFDataRef msgtype_oid_data = NULL;
296 require(msgtype_oid_data = scep_oid(messageType), out);
297 require(msgtype_value_data = printable_string_data(strlen(PKCSReq), PKCSReq), out);
298
299 CFDictionarySetValue(simple_attr, msgtype_oid_data, msgtype_value_data);
300 CFReleaseNull(msgtype_oid_data);
301 CFReleaseNull(msgtype_value_data);
302
303 /* random sender nonce, to be verified against recipient nonce in reply */
304 generate_sender_nonce(simple_attr);
305
306 /* XXX/cs remove auto-generation once managedconfig is no longer using this */
307 if (signer) {
308 self_signed_identity = signer;
309 CFRetain(self_signed_identity);
310 } else {
311 self_signed_identity = SecSCEPCreateTemporaryIdentity(publicKey, privateKey);
312
313 /* Add our temporary cert to the keychain for CMS decryption of
314 the reply. If we happened to have picked an existing UUID
315 we fail. We should pick a different UUID and try again. */
316 require(self_signed_identity, out);
317 CFDictionaryRef identity_add = CFDictionaryCreate(NULL,
318 &kSecValueRef, (const void **)&self_signed_identity, 1, NULL, NULL);
319 require_noerr_action(SecItemAdd(identity_add, NULL), out,
320 CFReleaseSafe(identity_add));
321 CFReleaseSafe(identity_add);
322 }
323 require(self_signed_identity, out);
324
325 signed_request = CFDataCreateMutable(kCFAllocatorDefault, 0);
326 require_noerr_action(SecCMSCreateSignedData(self_signed_identity, enveloped_data,
327 parameters, simple_attr, signed_request), out, CFReleaseNull(signed_request));
328
329
330 out:
331
332 CFReleaseSafe(simple_attr);
333 CFReleaseSafe(self_signed_identity);
334 CFReleaseSafe(enveloped_data);
335 CFReleaseSafe(csr);
336 return signed_request;
337 }
338
339
340 CFDataRef
341 SecSCEPCertifyRequest(CFDataRef request, SecIdentityRef ca_identity, CFDataRef serialno, bool pend_request)
342 {
343 CFDictionaryRef simple_attr = NULL;
344 SecCertificateRef ca_certificate = NULL;
345 SecKeyRef ca_public_key = NULL;
346 SecCertificateRef cert = NULL;
347 SecPolicyRef policy = NULL;
348 CFDataRef cert_pkcs7 = NULL;
349 CFMutableDataRef cert_msg = NULL;
350 CFMutableDataRef signed_reply = NULL;
351 SecTrustRef trust = NULL;
352 CFDataRef signed_content = NULL;
353 CFDictionaryRef signed_attributes = NULL;
354 SecCertificateRef signer_cert = NULL;
355 CFDataRef transid_oid_data = NULL, senderNonce_oid_data = NULL, transid_value = NULL;
356 CFDataRef subject = NULL, extensions = NULL, senderNonce_value = NULL;
357 CFStringRef challenge = NULL;
358 SecKeyRef tbsPublicKey = NULL;
359 CFMutableDataRef encrypted_content = NULL;
360 SecCertificateRef recipient = NULL;
361 CFDictionaryRef parameters = NULL;
362
363 require_noerr(SecIdentityCopyCertificate(ca_identity, &ca_certificate), out);
364 ca_public_key = SecCertificateCopyPublicKey(ca_certificate); /*@@@*/
365
366 /* unwrap outer layer: */
367 policy = SecPolicyCreateBasicX509();
368
369 require_noerr(SecCMSVerifyCopyDataAndAttributes(request, NULL,
370 policy, &trust, &signed_content, &signed_attributes), out);
371 /* remember signer: is signer certified by us, then re-certify, no challenge needed */
372 SecTrustResultType result;
373 require_noerr(SecTrustEvaluate(trust, &result), out);
374 require (signer_cert = SecTrustGetCertificateAtIndex(trust, 0), out);
375 bool recertify = !SecCertificateIsSignedBy(signer_cert, ca_public_key);
376
377 /* msgType should be certreq msg */
378 require(scep_attr_has_val(signed_attributes, messageType, PKCSReq), out);
379
380 /* remember transaction id just for reuse */
381 require(transid_oid_data = scep_oid(transId), out);
382 require(transid_value =
383 dictionary_array_value_1(signed_attributes, transid_oid_data), out);
384
385 /* senderNonce becomes recipientNonce */
386 require(senderNonce_oid_data = scep_oid(senderNonce), out);
387 require(senderNonce_value =
388 dictionary_array_value_1(signed_attributes, senderNonce_oid_data), out);
389
390 /* decrypt the request */
391 encrypted_content = CFDataCreateMutable(kCFAllocatorDefault, 0);
392 require_noerr(SecCMSDecryptEnvelopedData(signed_content, encrypted_content, &recipient), out);
393 require(recipient && CFEqual(ca_certificate, recipient), out);
394
395 /* verify CSR */
396 require(SecVerifyCertificateRequest(encrypted_content, &tbsPublicKey, &challenge, &subject, &extensions), out);
397 CFReleaseNull(encrypted_content);
398
399 /* @@@
400 // alternatively send a pending message
401 // pkistatus {{id-attributes pkiStatus(3)} "FAILURE"}
402 // failInfo {{id-attributes failInfo(4)} "the reason to reject"}
403 */
404
405 /* verify challenge - this would need to be a callout that can determine
406 the challenge appropriate for the subject */
407 if (!recertify)
408 require( challenge && (CFStringGetTypeID() == CFGetTypeID(challenge)) &&
409 CFEqual(CFSTR("magic"), challenge), out);
410
411 require(cert_msg = CFDataCreateMutable(kCFAllocatorDefault, 0), out);
412
413 if (!pend_request) {
414 /* sign cert */
415 cert = SecIdentitySignCertificate(ca_identity, serialno,
416 tbsPublicKey, subject, extensions);
417
418 /* degenerate cms with cert */
419 require (cert_pkcs7 = SecCMSCreateCertificatesOnlyMessage(cert), out);
420 CFReleaseNull(cert);
421
422 /* envelope for client */
423 require_noerr(SecCMSCreateEnvelopedData(signer_cert, NULL, cert_pkcs7, cert_msg), out);
424 CFReleaseNull(cert_pkcs7);
425 }
426
427 CFDataRef pki_status_oid = scep_oid(pkiStatus);
428 CFDataRef pki_status_value = pend_request ? scep_result(PKIStatusPENDING) : scep_result(PKIStatusSUCCESS);
429 CFDataRef message_type_oid = scep_oid(messageType), message_type_value = scep_result(CertRep);
430 const void *oid[] = { transid_oid_data, pki_status_oid, message_type_oid };
431 const void *value[] = { transid_value, pki_status_value, message_type_value };
432 simple_attr = CFDictionaryCreate(kCFAllocatorDefault, oid, value, array_size(oid),
433 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
434 CFReleaseSafe(pki_status_oid); CFReleaseSafe(pki_status_value);
435 CFReleaseSafe(message_type_oid); CFReleaseSafe(message_type_value);
436
437 /* sign with ra/ca cert and add attributes */
438 signed_reply = CFDataCreateMutable(kCFAllocatorDefault, 0);
439 const void *signing_params[] = { kSecCMSCertChainMode };
440 const void *signing_params_vals[] = { kSecCMSCertChainModeNone };
441 parameters = CFDictionaryCreate(kCFAllocatorDefault, signing_params, signing_params_vals, array_size(signing_params), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
442 require_noerr_action(SecCMSCreateSignedData(ca_identity, cert_msg, parameters, simple_attr, signed_reply), out, CFReleaseNull(signed_reply));
443
444 out:
445 CFReleaseSafe(ca_certificate);
446 CFReleaseSafe(ca_public_key);
447 CFReleaseSafe(cert);
448 CFReleaseSafe(cert_pkcs7);
449 CFReleaseSafe(cert_msg);
450 CFReleaseSafe(trust);
451 CFReleaseSafe(policy);
452 CFReleaseSafe(signed_content);
453 CFReleaseSafe(signed_attributes);
454 CFReleaseSafe(transid_oid_data);
455 CFReleaseSafe(senderNonce_oid_data);
456 CFReleaseSafe(subject);
457 CFReleaseSafe(extensions);
458 CFReleaseSafe(challenge);
459 CFReleaseSafe(tbsPublicKey);
460 CFReleaseSafe(encrypted_content);
461 CFReleaseSafe(simple_attr);
462 CFReleaseSafe(recipient);
463 CFReleaseSafe(parameters);
464
465 return signed_reply;
466 }
467
468 static CFStringRef
469 copy_signed_attr_printable_string_value(CFDictionaryRef signed_attributes, scep_attr_t attr)
470 {
471 CFStringRef printable_string = NULL;
472 CFDataRef key_oid = NULL;
473
474 key_oid = scep_oid(attr);
475 require(key_oid, out);
476
477 CFArrayRef values = (CFArrayRef)CFDictionaryGetValue(signed_attributes, key_oid);
478 require_quiet(values && (CFGetTypeID(values) == CFArrayGetTypeID())
479 && (CFArrayGetCount(values) == 1), out);
480 CFDataRef value = CFArrayGetValueAtIndex(values, 0);
481 const uint8_t *bytes = CFDataGetBytePtr(value);
482 size_t length = CFDataGetLength(value);
483 require(length >= 2, out);
484 require(bytes[0] == 0x13, out);
485 /* no scep responses defined that are longer */
486 require(!(bytes[1] & 0x80) && (bytes[1] == length-2), out);
487 printable_string = CFStringCreateWithBytes(kCFAllocatorDefault,
488 bytes + 2, length - 2, kCFStringEncodingASCII, false);
489 out:
490 CFReleaseSafe(key_oid);
491
492 return printable_string;
493 }
494
495 CFArrayRef
496 SecSCEPVerifyReply(CFDataRef request, CFDataRef reply, CFTypeRef ca_certificates,
497 CFErrorRef *server_error)
498 {
499 SecKeyRef ca_public_key = NULL;
500 SecCertificateRef cert = NULL;
501 SecPolicyRef policy = NULL;
502 CFDataRef cert_msg = NULL;
503 CFMutableDataRef enc_cert_msg = NULL;
504 SecTrustRef trust = NULL;
505 CFDataRef signed_content = NULL;
506 CFDictionaryRef signed_attributes = NULL;
507 CFDictionaryRef attributes = NULL;
508 SecCertificateRef signer_cert = NULL;
509
510 CFMutableDataRef encrypted_content = NULL;
511 SecCertificateRef recipient = NULL;
512 CFArrayRef certificates = NULL;
513
514 SecCertificateRef reply_signer = NULL;
515
516 CFStringRef msg_type = NULL;
517 CFStringRef pki_status = NULL;
518
519 if (CFGetTypeID(ca_certificates) == SecCertificateGetTypeID()) {
520 reply_signer = (SecCertificateRef)ca_certificates;
521 } else if (CFGetTypeID(ca_certificates) == CFArrayGetTypeID()) {
522 CFIndex reply_signer_count = CFArrayGetCount(ca_certificates);
523 if (reply_signer_count > 1) {
524 /* get the signer cert */
525 reply_signer = (SecCertificateRef)CFArrayGetValueAtIndex(ca_certificates, 1);
526 } else if (reply_signer_count == 1) {
527 /* if there is at least one we'll assume it's sign+encrypt */
528 reply_signer = (SecCertificateRef)CFArrayGetValueAtIndex(ca_certificates, 0);
529 }
530 }
531 require(reply_signer, out);
532
533 /* unwrap outer layer */
534 policy = SecPolicyCreateBasicX509();
535 CFArrayRef additional_certificates = CFArrayCreate(kCFAllocatorDefault, (const void **)&reply_signer, 1, &kCFTypeArrayCallBacks);
536 require_noerr(SecCMSVerifySignedData(reply, NULL,
537 policy, &trust, additional_certificates, &signed_content, &attributes), out);
538 CFReleaseSafe(additional_certificates);
539 if (attributes)
540 signed_attributes = CFDictionaryGetValue(attributes, kSecCMSSignedAttributes);
541
542 /* response should be signed by ra */
543 SecTrustResultType result;
544 require_noerr(SecTrustEvaluate(trust, &result), out);
545 require(signer_cert = SecTrustGetCertificateAtIndex(trust, 0), out);
546 require(CFEqual(reply_signer, signer_cert), out);
547
548 /* msgType should be certreq msg */
549 require(signed_attributes, out);
550 msg_type = copy_signed_attr_printable_string_value(signed_attributes, messageType);
551 pki_status = copy_signed_attr_printable_string_value(signed_attributes, pkiStatus);
552
553 if (msg_type || pki_status) {
554 require(msg_type && CFEqual(msg_type, CFSTR("3")), out);
555
556 require(pki_status, out);
557 if (CFEqual(pki_status, CFSTR("2"))) {
558 goto out; // FAILURE, the end (return NULL)
559 } else if (CFEqual(pki_status, CFSTR("3"))) {
560 CFDataRef transid_oid_data = NULL, transid_value = NULL;
561 require(transid_oid_data = scep_oid(transId), out);
562 require(transid_value = dictionary_array_value_1(signed_attributes, transid_oid_data), out);
563 CFDictionaryRef err_dict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&transid_oid_data, (const void **)&transid_value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
564 *server_error = CFErrorCreate(kCFAllocatorDefault,
565 CFSTR("PENDING"), 3, err_dict);
566 CFReleaseSafe(err_dict);
567 CFReleaseSafe(transid_oid_data);
568 goto out;
569 }
570 require(CFEqual(pki_status, CFSTR("0")), out);
571 }
572
573 // can we decode the request?
574 encrypted_content = CFDataCreateMutable(kCFAllocatorDefault, 0);
575 require_noerr(SecCMSDecryptEnvelopedData(signed_content, encrypted_content, &recipient), out);
576 require(recipient, out);
577 // verify recipient belongs with our private key
578
579 // verify CSR:
580 require(certificates = SecCMSCertificatesOnlyMessageCopyCertificates(encrypted_content), out);
581
582 // recipient is either our temporary self-signed cert or the old cert we just used
583 // to recertify. if we have new certificates and have stored them successfully we
584 // can now get rid of the cert.
585 /* XXX/cs
586 This should move outside of thise function when we force a signer
587 to be passed in */
588 CFDictionaryRef cert_delete = CFDictionaryCreate(NULL,
589 &kSecValueRef, (const void **)&recipient, 1, NULL, NULL);
590 require_noerr_action(SecItemDelete(cert_delete), out,
591 CFReleaseSafe(cert_delete));
592 CFReleaseSafe(cert_delete);
593
594 out:
595 CFReleaseSafe(ca_public_key);
596 CFReleaseSafe(cert);
597 CFReleaseSafe(cert_msg);
598 CFReleaseSafe(enc_cert_msg);
599 CFReleaseSafe(trust);
600 CFReleaseSafe(policy);
601 CFReleaseSafe(signed_content);
602 CFReleaseSafe(encrypted_content);
603 CFReleaseSafe(recipient);
604 CFReleaseSafe(msg_type);
605 CFReleaseSafe(pki_status);
606 CFReleaseSafe(attributes);
607
608 return certificates;
609 }
610
611 OSStatus SecSCEPValidateCACertMessage(CFArrayRef certs,
612 CFDataRef ca_fingerprint,
613 SecCertificateRef *ca_certificate,
614 SecCertificateRef *ra_signing_certificate,
615 SecCertificateRef *ra_encryption_certificate)
616 {
617 OSStatus status = errSecParam;
618 SecCertificateRef _ca_certificate = NULL, _ra_signing_certificate = NULL,
619 _ra_encryption_certificate = NULL, _ra_certificate = NULL;
620
621 CFIndex j, count = CFArrayGetCount(certs);
622 CFMutableArrayRef chain = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
623 SecPolicyRef policy = SecPolicyCreateBasicX509();
624 SecTrustRef trust = NULL;
625 require(chain, out);
626 for (j=0; j<count; j++) {
627 const void *candidate_leaf = CFArrayGetValueAtIndex(certs, j);
628 CFArrayRemoveAllValues(chain);
629 CFArraySetValueAtIndex(chain, 0, candidate_leaf);
630 CFArrayAppendArray(chain, certs, CFRangeMake(0, count));
631 CFArrayRemoveValueAtIndex(chain, 1 + j);
632 require_noerr(SecTrustCreateWithCertificates(chain,
633 policy, &trust), out);
634 SecTrustResultType trust_result;
635 SecTrustEvaluate(trust, &trust_result);
636 CFIndex chain_count = SecTrustGetCertificateCount(trust);
637 secdebug("scep", "candidate leaf: %@ forms chain of length %" PRIdCFIndex, candidate_leaf, chain_count);
638 if (chain_count > 1) {
639 SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
640 SecCertificateRef ca_leaf = SecTrustGetCertificateAtIndex(trust, chain_count - 1);
641 if (!_ca_certificate) {
642 if (ca_fingerprint) {
643 secdebug("scep", "checking ca %@ against fingerprint %@", ca_leaf, ca_fingerprint);
644 uint8_t ca_hash[CC_SHA1_DIGEST_LENGTH]; /*max(md5,sha-1)*/
645 CFDataRef ca_cert_data = SecCertificateCopyData(ca_leaf);
646 require(ca_cert_data, out);
647 size_t ca_data_len = CFDataGetLength(ca_cert_data);
648 size_t ca_fingerprint_len = CFDataGetLength(ca_fingerprint);
649 const uint8_t *ca_data = CFDataGetBytePtr(ca_cert_data);
650 require(ca_data_len && ca_data, out);
651 require(ca_data_len<UINT32_MAX, out);
652 switch (ca_fingerprint_len) {
653 case CC_MD5_DIGEST_LENGTH:
654 CC_MD5(ca_data, (CC_LONG)ca_data_len, ca_hash);
655 break;
656
657 case CC_SHA1_DIGEST_LENGTH:
658 CCDigest(kCCDigestSHA1, ca_data, (CC_LONG)ca_data_len, ca_hash);
659 break;
660
661 default:
662 goto out;
663 }
664 CFRelease(ca_cert_data);
665 CFDataRef ca_hash_cfdata = CFDataCreate(kCFAllocatorDefault,
666 ca_hash, ca_fingerprint_len);
667 require(ca_hash_cfdata, out);
668 require_action(CFEqual(ca_fingerprint, ca_hash_cfdata),
669 out, CFRelease(ca_hash_cfdata));
670 CFRelease(ca_hash_cfdata);
671 }
672 _ca_certificate = ca_leaf;
673 CFRetain(ca_leaf);
674 } else {
675 // if ca_certificate is already set, this should be the same
676 require(CFEqual(_ca_certificate, ca_leaf), out);
677 }
678
679 // is leaf allowed to sign and/or encrypt?
680 SecKeyUsage key_usage = SecCertificateGetKeyUsage(leaf);
681 bool can_sign = (key_usage & kSecKeyUsageDigitalSignature);
682 bool can_enc = (key_usage & kSecKeyUsageKeyEncipherment);
683 if (!_ra_certificate && can_sign && can_enc) {
684 _ra_certificate = leaf;
685 CFRetain(leaf);
686 }
687 else if (!_ra_encryption_certificate && !can_sign && can_enc) {
688 _ra_encryption_certificate = leaf;
689 CFRetain(leaf);
690 }
691 else if (!_ra_signing_certificate && !can_enc && can_sign) {
692 _ra_signing_certificate = leaf;
693 CFRetain(leaf);
694 }
695 }
696 if (trust) { CFRelease(trust); trust = NULL; }
697 }
698
699 // we should have both a ca certificate and at least one ra certificate now
700 require(_ca_certificate, out);
701 require(_ra_certificate ||
702 (_ra_signing_certificate && _ra_encryption_certificate), out);
703
704 if (ca_certificate) {
705 *ca_certificate = _ca_certificate;
706 _ca_certificate = NULL;
707 }
708 if (_ra_signing_certificate && _ra_encryption_certificate) {
709 if (ra_signing_certificate) {
710 *ra_signing_certificate = _ra_signing_certificate;
711 _ra_signing_certificate = NULL;
712 }
713 if (ra_encryption_certificate) {
714 *ra_encryption_certificate = _ra_encryption_certificate;
715 _ra_encryption_certificate = NULL;
716 }
717 } else if (_ra_certificate) {
718 if (ra_signing_certificate) {
719 *ra_signing_certificate = _ra_certificate;
720 _ra_certificate = NULL;
721 }
722 }
723
724 status = errSecSuccess;
725
726 out:
727 if (_ra_encryption_certificate) CFRelease(_ra_encryption_certificate);
728 if (_ra_signing_certificate) CFRelease(_ra_signing_certificate);
729 if (_ca_certificate) CFRelease(_ca_certificate);
730 if (policy) CFRelease(policy);
731 if (trust) CFRelease(trust);
732 if (chain) CFRelease(chain);
733 return status;
734
735 }
736
737
738 /*!
739 @function SecSCEPGetCertInitial
740 @abstract generate a scep cert initial request, to be presented to
741 a scep server, in case the first request timed out
742 */
743
744 // XXX/cs pass CA/RA certificates as a CFTypeRef: one or more certificates for ca_certificate and recipient
745
746 CFDataRef
747 SecSCEPGetCertInitial(SecCertificateRef ca_certificate, CFArrayRef subject, CFDictionaryRef parameters,
748 CFDictionaryRef signed_attrs, SecIdentityRef signer, CFTypeRef recipient)
749 {
750 CFMutableDataRef signed_request = NULL;
751 CFMutableDictionaryRef simple_attr = NULL;
752 CFDataRef pki_message_contents = NULL;
753 CFMutableDataRef enveloped_data = NULL;
754
755 require(signed_attrs, out);
756 require(pki_message_contents = SecGenerateCertificateRequestSubject(ca_certificate, subject), out);
757 require(enveloped_data = CFDataCreateMutable(kCFAllocatorDefault, 0), out);
758 require_noerr(SecCMSCreateEnvelopedData(recipient, parameters, pki_message_contents, enveloped_data), out);
759
760 /* remember transaction id just for reuse */
761 simple_attr = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 3, signed_attrs);
762
763 /* message type: GetCertInitial (20) */
764 CFDataRef msgtype_value_data = NULL;
765 CFDataRef msgtype_oid_data = NULL;
766 require(msgtype_oid_data = scep_oid(messageType), out);
767 require(msgtype_value_data = printable_string_data(sizeof(GetCertInitial) - 1, GetCertInitial), out);
768 CFDictionarySetValue(simple_attr, msgtype_oid_data, msgtype_value_data);
769 CFReleaseNull(msgtype_oid_data);
770 CFReleaseNull(msgtype_value_data);
771
772 /* random sender nonce, to be verified against recipient nonce in reply */
773 generate_sender_nonce(simple_attr);
774 signed_request = CFDataCreateMutable(kCFAllocatorDefault, 0);
775 require_noerr_action(SecCMSCreateSignedData(signer, enveloped_data,
776 parameters, simple_attr, signed_request), out, CFReleaseNull(signed_request));
777
778 out:
779 CFReleaseSafe(simple_attr);
780 CFReleaseSafe(pki_message_contents);
781 CFReleaseSafe(enveloped_data);
782 return signed_request;
783 }
784
785
786 /*
787 +----------------+-----------------+---------------------------+
788 | Attribute | Encoding | Comment |
789 +----------------+-----------------+---------------------------+
790 | transactionID | PrintableString | Decimal value as a string |
791 | messageType | PrintableString | Decimal value as a string |
792 | pkiStatus | PrintableString | Decimal value as a string |
793 | failInfo | PrintableString | Decimal value as a string |
794 | senderNonce | OctetString | |
795 | recipientNonce | OctetString | |
796 +----------------+-----------------+---------------------------+
797
798 4.2.1. transactionID
799
800 The transactionID is an attribute which uniquely identifies a
801 transaction. This attribute is required in all PKI messages.
802
803 Because the enrollment transaction could be interrupted by various
804 errors, including network connection errors or client reboot, the
805 SCEP client generates a transaction identifier by calculating a hash
806 on the public key value for which the enrollment is requested. This
807 retains the same transaction identifier throughout the enrollment
808 transaction, even if the client has rebooted or timed out, and issues
809 a new enrollment request for the same key pair.
810
811 It also provides the way for the CA to uniquely identify a
812 transaction in its database. At the requester side, it generates a
813 transaction identifier which is included in PKCSReq. If the CA
814 returns a response of PENDING, the requester will poll by
815 periodically sending out GetCertInitial with the same transaction
816 identifier until either a response other than PENDING is obtained, or
817 the configured maximum time has elapsed.
818
819 For non-enrollment message (for example GetCert and GetCRL), the
820 transactionID should be a number unique to the client.
821
822
823 4.2.2. messageType
824
825 The messageType attribute specify the type of operation performed by
826 the transaction. This attribute is required in all PKI messages.
827 Currently, the following message types are defined:
828
829 o PKCSReq (19) -- PKCS#10 [RFC2986] certificate request
830
831 o CertRep (3) -- Response to certificate or CRL request
832
833 o GetCertInitial (20) -- Certificate polling in manual enrollment
834
835 o GetCert (21) -- Retrieve a certificate
836
837 o GetCRL (22) -- Retrieve a CRL
838
839 4.2.3. pkiStatus
840
841 All response message will include transaction status information
842 which is defined as pkiStatus attribute:
843
844 o SUCCESS (0) -- request granted
845
846 o FAILURE (2) -- request rejected. This also requires a failInfo
847 attribute to be present, as defined in section 4.2.4.
848
849 o PENDING (3) -- request pending for manual approval
850
851
852 4.2.4. failInfo
853
854 The failInfo attribute will contain one of the following failure
855 reasons:
856
857 o badAlg (0) -- Unrecognized or unsupported algorithm ident
858
859 o badMessageCheck (1) -- integrity check failed
860
861 o badRequest (2) -- transaction not permitted or supported
862
863 o badTime (3) -- Message time field was not sufficiently close to
864 the system time
865
866 o badCertId (4) -- No certificate could be identified matching the
867 provided criteria
868
869 4.2.5. senderNonce and responderNonce
870
871 The attributes of senderNonce and recipientNonce are the 16 byte
872 random numbers generated for each transaction to prevent the replay
873 attack.
874
875 When a requester sends a PKI message to the server, a senderNonce is
876 included in the message. After the server processes the request, it
877 will send back the requester senderNonce as the recipientNonce and
878 generates another nonce as the senderNonce in the response message.
879 Because the proposed PKI protocol is a two-way communication
880 protocol, it is clear that the nonce can only be used by the
881 requester to prevent the replay. The server has to employ extra
882 state related information to prevent a replay attack.
883
884 */