]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecSCEP.c
Security-58286.41.2.tar.gz
[apple/security.git] / OSX / sec / Security / SecSCEP.c
1 /*
2 * Copyright (c) 2008-2010,2012-2014 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 CF_RETURNS_RETAINED 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 __unused static const char GetCert[] = "21";
91 __unused static const char GetCRL[] = "22";
92 static const char PKIStatusSUCCESS[] = "0";
93 __unused static const char PKIStatusFAILURE[] = "2";
94 static const char PKIStatusPENDING[] = "3";
95
96 static CF_RETURNS_RETAINED 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 CF_RETURNS_NOT_RETAINED 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 CF_RETURNS_RETAINED 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 CF_RETURNS_RETAINED 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 int 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 int status = 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 return status;
195 }
196
197 SecIdentityRef SecSCEPCreateTemporaryIdentity(SecKeyRef publicKey, SecKeyRef privateKey)
198 {
199 int key_usage = kSecKeyUsageDigitalSignature | kSecKeyUsageKeyEncipherment;
200 CFDictionaryRef self_signed_parameters = NULL;
201 CFNumberRef key_usage_num = NULL;
202 SecCertificateRef self_signed_certificate = NULL;
203 SecIdentityRef self_signed_identity = NULL;
204 CFStringRef cn_uuid = NULL;
205 CFArrayRef cn_dn = NULL, cn_dns = NULL, unique_rdns = NULL;
206
207 key_usage_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &key_usage);
208 require(key_usage_num, out);
209
210 const void *key[] = { kSecCertificateKeyUsage };
211 const void *val[] = { key_usage_num };
212 self_signed_parameters = CFDictionaryCreate(kCFAllocatorDefault,
213 key, val, array_size(key),
214 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
215 require(self_signed_parameters, out);
216
217 char uuid_string[37] = {};
218 uuid_t uuid;
219 uuid_generate_random(uuid);
220 uuid_unparse(uuid, uuid_string);
221 cn_uuid = CFStringCreateWithCString(kCFAllocatorDefault, uuid_string, kCFStringEncodingASCII);
222 require(cn_uuid, out);
223 const void * cn[] = { kSecOidCommonName, cn_uuid };
224 cn_dn = CFArrayCreate(kCFAllocatorDefault, cn, 2, NULL);
225 require(cn_dn, out);
226 cn_dns = CFArrayCreate(kCFAllocatorDefault, (const void **)&cn_dn, 1, NULL);
227 require(cn_dns, out);
228 unique_rdns = CFArrayCreate(kCFAllocatorDefault, (const void **)&cn_dns, 1, NULL);
229 require(unique_rdns, out);
230
231 self_signed_certificate = SecGenerateSelfSignedCertificate(unique_rdns, self_signed_parameters, publicKey, privateKey);
232 require(self_signed_certificate, out);
233 self_signed_identity = SecIdentityCreate(kCFAllocatorDefault, self_signed_certificate, privateKey);
234
235 out:
236 CFReleaseSafe(key_usage_num);
237 CFReleaseSafe(self_signed_parameters);
238 CFReleaseSafe(self_signed_certificate);
239 CFReleaseSafe(unique_rdns);
240 CFReleaseSafe(cn_dns);
241 CFReleaseSafe(cn_dn);
242 CFReleaseSafe(cn_uuid);
243
244 return self_signed_identity;
245 }
246
247 CFDataRef
248 SecSCEPGenerateCertificateRequest(CFArrayRef subject, CFDictionaryRef parameters,
249 SecKeyRef publicKey, SecKeyRef privateKey,
250 SecIdentityRef signer, CFTypeRef recipients)
251 {
252 CFDataRef csr = NULL;
253 CFMutableDataRef enveloped_data = NULL;
254 CFMutableDictionaryRef simple_attr = NULL;
255 SecIdentityRef self_signed_identity = NULL;
256 CFMutableDataRef signed_request = NULL;
257 SecCertificateRef recipient = NULL;
258 CFDataRef msgtype_value_data = NULL;
259 CFDataRef msgtype_oid_data = NULL;
260
261 if (CFGetTypeID(recipients) == SecCertificateGetTypeID()) {
262 recipient = (SecCertificateRef)recipients;
263 } else if (CFGetTypeID(recipients) == CFArrayGetTypeID()) {
264 CFIndex recipient_count = CFArrayGetCount(recipients);
265 if (recipient_count > 1) {
266 /* get the encryption cert */
267 recipient = (SecCertificateRef)CFArrayGetValueAtIndex(recipients, 0);
268 } else if (recipient_count == 1) {
269 /* if there is at least one we'll assume it's sign+encrypt */
270 recipient = (SecCertificateRef)CFArrayGetValueAtIndex(recipients, 0);
271 }
272 }
273 require(recipient, out);
274
275 require(csr = SecGenerateCertificateRequest(subject, parameters, publicKey, privateKey), out);
276 require(enveloped_data = CFDataCreateMutable(kCFAllocatorDefault, 0), out);
277 require_noerr(SecCMSCreateEnvelopedData(recipient, parameters, csr, enveloped_data), out);
278 CFReleaseNull(csr);
279
280 simple_attr = CFDictionaryCreateMutable(kCFAllocatorDefault, 3,
281 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
282
283 /* generate a transaction id: hex encoded pubkey hash */
284 CFDataRef public_key_hash = pubkeyhash(publicKey);
285 CFDataRef public_key_hash_hex = hexencode(public_key_hash);
286 CFReleaseSafe(public_key_hash);
287 CFDataRef transid_oid_data = scep_oid(transId);
288 CFDataRef transid_data = printable_string_data(CFDataGetLength(public_key_hash_hex),
289 (const char *)CFDataGetBytePtr(public_key_hash_hex));
290 CFReleaseSafe(public_key_hash_hex);
291
292 CFDictionarySetValue(simple_attr, transid_oid_data, transid_data);
293 CFReleaseNull(transid_oid_data);
294 CFReleaseNull(transid_data);
295
296 /* message type: PKCSReq (19) */
297 msgtype_value_data = NULL;
298 msgtype_oid_data = NULL;
299 require(msgtype_oid_data = scep_oid(messageType), out);
300 require(msgtype_value_data = printable_string_data(strlen(PKCSReq), PKCSReq), out);
301
302 CFDictionarySetValue(simple_attr, msgtype_oid_data, msgtype_value_data);
303 CFReleaseNull(msgtype_oid_data);
304 CFReleaseNull(msgtype_value_data);
305
306 /* random sender nonce, to be verified against recipient nonce in reply */
307 require(generate_sender_nonce(simple_attr) == errSecSuccess, out);
308
309 /* XXX/cs remove auto-generation once managedconfig is no longer using this */
310 if (signer) {
311 self_signed_identity = signer;
312 CFRetain(self_signed_identity);
313 } else {
314 self_signed_identity = SecSCEPCreateTemporaryIdentity(publicKey, privateKey);
315
316 /* Add our temporary cert to the keychain for CMS decryption of
317 the reply. If we happened to have picked an existing UUID
318 we fail. We should pick a different UUID and try again. */
319 require(self_signed_identity, out);
320 CFDictionaryRef identity_add = CFDictionaryCreate(NULL,
321 (const void **)&kSecValueRef, (const void **)&self_signed_identity, 1, NULL, NULL);
322 require_noerr_action(SecItemAdd(identity_add, NULL), out,
323 CFReleaseSafe(identity_add));
324 CFReleaseSafe(identity_add);
325 }
326 require(self_signed_identity, out);
327
328 signed_request = CFDataCreateMutable(kCFAllocatorDefault, 0);
329 require_noerr_action(SecCMSCreateSignedData(self_signed_identity, enveloped_data,
330 parameters, simple_attr, signed_request), out, CFReleaseNull(signed_request));
331
332
333 out:
334
335 CFReleaseSafe(simple_attr);
336 CFReleaseSafe(msgtype_oid_data);
337 CFReleaseSafe(msgtype_value_data);
338 CFReleaseSafe(self_signed_identity);
339 CFReleaseSafe(enveloped_data);
340 CFReleaseSafe(csr);
341 return signed_request;
342 }
343
344
345 CFDataRef
346 SecSCEPCertifyRequest(CFDataRef request, SecIdentityRef ca_identity, CFDataRef serialno, bool pend_request)
347 {
348 CFDictionaryRef simple_attr = NULL;
349 SecCertificateRef ca_certificate = NULL;
350 SecKeyRef ca_public_key = NULL;
351 SecCertificateRef cert = NULL;
352 SecPolicyRef policy = NULL;
353 CFDataRef cert_pkcs7 = NULL;
354 CFMutableDataRef cert_msg = NULL;
355 CFMutableDataRef signed_reply = NULL;
356 SecTrustRef trust = NULL;
357 CFDataRef signed_content = NULL;
358 CFDictionaryRef signed_attributes = NULL;
359 SecCertificateRef signer_cert = NULL;
360 CFDataRef transid_oid_data = NULL, senderNonce_oid_data = NULL, transid_value = NULL;
361 CFDataRef subject = NULL, extensions = NULL, senderNonce_value = NULL;
362 CFStringRef challenge = NULL;
363 SecKeyRef tbsPublicKey = NULL;
364 CFMutableDataRef encrypted_content = NULL;
365 SecCertificateRef recipient = NULL;
366 CFDictionaryRef parameters = NULL;
367
368 require_noerr(SecIdentityCopyCertificate(ca_identity, &ca_certificate), out);
369 #if TARGET_OS_IPHONE
370 ca_public_key = SecCertificateCopyPublicKey(ca_certificate); /*@@@*/
371 #else
372 ca_public_key = SecCertificateCopyPublicKey_ios(ca_certificate);
373 #endif
374
375 /* unwrap outer layer: */
376 policy = SecPolicyCreateBasicX509();
377
378 require_noerr(SecCMSVerifyCopyDataAndAttributes(request, NULL,
379 policy, &trust, &signed_content, &signed_attributes), out);
380 /* remember signer: is signer certified by us, then re-certify, no challenge needed */
381 SecTrustResultType result;
382 require_noerr(SecTrustEvaluate(trust, &result), out);
383 require (signer_cert = SecTrustGetCertificateAtIndex(trust, 0), out);
384 bool recertify = !SecCertificateIsSignedBy(signer_cert, ca_public_key);
385
386 /* msgType should be certreq msg */
387 require(scep_attr_has_val(signed_attributes, messageType, PKCSReq), out);
388
389 /* remember transaction id just for reuse */
390 require(transid_oid_data = scep_oid(transId), out);
391 require(transid_value =
392 dictionary_array_value_1(signed_attributes, transid_oid_data), out);
393
394 /* senderNonce becomes recipientNonce */
395 require(senderNonce_oid_data = scep_oid(senderNonce), out);
396 require(senderNonce_value =
397 dictionary_array_value_1(signed_attributes, senderNonce_oid_data), out);
398
399 /* decrypt the request */
400 encrypted_content = CFDataCreateMutable(kCFAllocatorDefault, 0);
401 require_noerr(SecCMSDecryptEnvelopedData(signed_content, encrypted_content, &recipient), out);
402 require(recipient && CFEqual(ca_certificate, recipient), out);
403
404 /* verify CSR */
405 require(SecVerifyCertificateRequest(encrypted_content, &tbsPublicKey, &challenge, &subject, &extensions), out);
406 CFReleaseNull(encrypted_content);
407
408 /* @@@
409 // alternatively send a pending message
410 // pkistatus {{id-attributes pkiStatus(3)} "FAILURE"}
411 // failInfo {{id-attributes failInfo(4)} "the reason to reject"}
412 */
413
414 /* verify challenge - this would need to be a callout that can determine
415 the challenge appropriate for the subject */
416 if (!recertify)
417 require( challenge && (CFStringGetTypeID() == CFGetTypeID(challenge)) &&
418 CFEqual(CFSTR("magic"), challenge), out);
419
420 require(cert_msg = CFDataCreateMutable(kCFAllocatorDefault, 0), out);
421
422 if (!pend_request) {
423 /* sign cert */
424 cert = SecIdentitySignCertificate(ca_identity, serialno,
425 tbsPublicKey, subject, extensions);
426
427 /* degenerate cms with cert */
428 require (cert_pkcs7 = SecCMSCreateCertificatesOnlyMessage(cert), out);
429 CFReleaseNull(cert);
430
431 /* envelope for client */
432 require_noerr(SecCMSCreateEnvelopedData(signer_cert, NULL, cert_pkcs7, cert_msg), out);
433 CFReleaseNull(cert_pkcs7);
434 }
435
436 CFDataRef pki_status_oid = scep_oid(pkiStatus);
437 CFDataRef pki_status_value = pend_request ? scep_result(PKIStatusPENDING) : scep_result(PKIStatusSUCCESS);
438 CFDataRef message_type_oid = scep_oid(messageType), message_type_value = scep_result(CertRep);
439 const void *oid[] = { transid_oid_data, pki_status_oid, message_type_oid };
440 const void *value[] = { transid_value, pki_status_value, message_type_value };
441 simple_attr = CFDictionaryCreate(kCFAllocatorDefault, oid, value, array_size(oid),
442 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
443 CFReleaseSafe(pki_status_oid); CFReleaseSafe(pki_status_value);
444 CFReleaseSafe(message_type_oid); CFReleaseSafe(message_type_value);
445
446 /* sign with ra/ca cert and add attributes */
447 signed_reply = CFDataCreateMutable(kCFAllocatorDefault, 0);
448 const void *signing_params[] = { kSecCMSCertChainMode };
449 const void *signing_params_vals[] = { kSecCMSCertChainModeNone };
450 parameters = CFDictionaryCreate(kCFAllocatorDefault, signing_params, signing_params_vals, array_size(signing_params), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
451 require_noerr_action(SecCMSCreateSignedData(ca_identity, cert_msg, parameters, simple_attr, signed_reply), out, CFReleaseNull(signed_reply));
452
453 out:
454 CFReleaseSafe(ca_certificate);
455 CFReleaseSafe(ca_public_key);
456 CFReleaseSafe(cert);
457 CFReleaseSafe(cert_pkcs7);
458 CFReleaseSafe(cert_msg);
459 CFReleaseSafe(trust);
460 CFReleaseSafe(policy);
461 CFReleaseSafe(signed_content);
462 CFReleaseSafe(signed_attributes);
463 CFReleaseSafe(transid_oid_data);
464 CFReleaseSafe(senderNonce_oid_data);
465 CFReleaseSafe(subject);
466 CFReleaseSafe(extensions);
467 CFReleaseSafe(challenge);
468 CFReleaseSafe(tbsPublicKey);
469 CFReleaseSafe(encrypted_content);
470 CFReleaseSafe(simple_attr);
471 CFReleaseSafe(recipient);
472 CFReleaseSafe(parameters);
473
474 return signed_reply;
475 }
476
477 static CFStringRef
478 copy_signed_attr_printable_string_value(CFDictionaryRef signed_attributes, scep_attr_t attr)
479 {
480 CFStringRef printable_string = NULL;
481 CFDataRef key_oid = NULL;
482
483 key_oid = scep_oid(attr);
484 require(key_oid, out);
485
486 CFArrayRef values = (CFArrayRef)CFDictionaryGetValue(signed_attributes, key_oid);
487 require_quiet(values && (CFGetTypeID(values) == CFArrayGetTypeID())
488 && (CFArrayGetCount(values) == 1), out);
489 CFDataRef value = CFArrayGetValueAtIndex(values, 0);
490 const uint8_t *bytes = CFDataGetBytePtr(value);
491 size_t length = CFDataGetLength(value);
492 require(length >= 2, out);
493 require(bytes[0] == 0x13, out);
494 /* no scep responses defined that are longer */
495 require(!(bytes[1] & 0x80) && (bytes[1] == length-2), out);
496 printable_string = CFStringCreateWithBytes(kCFAllocatorDefault,
497 bytes + 2, length - 2, kCFStringEncodingASCII, false);
498 out:
499 CFReleaseSafe(key_oid);
500
501 return printable_string;
502 }
503
504 CFArrayRef
505 SecSCEPVerifyReply(CFDataRef request, CFDataRef reply, CFTypeRef ca_certificates,
506 CFErrorRef *server_error)
507 {
508 SecKeyRef ca_public_key = NULL;
509 SecCertificateRef cert = NULL;
510 SecPolicyRef policy = NULL;
511 CFDataRef cert_msg = NULL;
512 CFMutableDataRef enc_cert_msg = NULL;
513 SecTrustRef trust = NULL;
514 CFDataRef signed_content = NULL;
515 CFDictionaryRef signed_attributes = NULL;
516 CFDictionaryRef attributes = NULL;
517 SecCertificateRef signer_cert = NULL;
518
519 CFMutableDataRef encrypted_content = NULL;
520 SecCertificateRef recipient = NULL;
521 CFArrayRef certificates = NULL;
522
523 SecCertificateRef reply_signer = NULL;
524
525 CFStringRef msg_type = NULL;
526 CFStringRef pki_status = NULL;
527
528 if (CFGetTypeID(ca_certificates) == SecCertificateGetTypeID()) {
529 reply_signer = (SecCertificateRef)ca_certificates;
530 } else if (CFGetTypeID(ca_certificates) == CFArrayGetTypeID()) {
531 CFIndex reply_signer_count = CFArrayGetCount(ca_certificates);
532 if (reply_signer_count > 1) {
533 /* get the signer cert */
534 reply_signer = (SecCertificateRef)CFArrayGetValueAtIndex(ca_certificates, 1);
535 } else if (reply_signer_count == 1) {
536 /* if there is at least one we'll assume it's sign+encrypt */
537 reply_signer = (SecCertificateRef)CFArrayGetValueAtIndex(ca_certificates, 0);
538 }
539 }
540 require(reply_signer, out);
541
542 /* unwrap outer layer */
543 policy = SecPolicyCreateBasicX509();
544 CFArrayRef additional_certificates = CFArrayCreate(kCFAllocatorDefault, (const void **)&reply_signer, 1, &kCFTypeArrayCallBacks);
545 require_noerr(SecCMSVerifySignedData(reply, NULL,
546 policy, &trust, additional_certificates, &signed_content, &attributes), out);
547 CFReleaseSafe(additional_certificates);
548 if (attributes)
549 signed_attributes = CFDictionaryGetValue(attributes, kSecCMSSignedAttributes);
550
551 /* response should be signed by ra */
552 SecTrustResultType result;
553 require_noerr(SecTrustEvaluate(trust, &result), out);
554 require(signer_cert = SecTrustGetCertificateAtIndex(trust, 0), out);
555 require(CFEqual(reply_signer, signer_cert), out);
556
557 /* msgType should be certreq msg */
558 require(signed_attributes, out);
559 msg_type = copy_signed_attr_printable_string_value(signed_attributes, messageType);
560 pki_status = copy_signed_attr_printable_string_value(signed_attributes, pkiStatus);
561
562 if (msg_type || pki_status) {
563 require(msg_type && CFEqual(msg_type, CFSTR("3")), out);
564
565 require(pki_status, out);
566 if (CFEqual(pki_status, CFSTR("2"))) {
567 goto out; // FAILURE, the end (return NULL)
568 } else if (CFEqual(pki_status, CFSTR("3"))) {
569 CFDataRef transid_oid_data = NULL, transid_value = NULL;
570 CFDictionaryRef err_dict = NULL;
571 require(transid_oid_data = scep_oid(transId), inner_out);
572 require(transid_value = dictionary_array_value_1(signed_attributes, transid_oid_data), inner_out);
573 err_dict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&transid_oid_data, (const void **)&transid_value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
574 if (server_error)
575 *server_error = CFErrorCreate(kCFAllocatorDefault, CFSTR("PENDING"), 3, err_dict);
576 inner_out:
577 CFReleaseSafe(err_dict);
578 CFReleaseSafe(transid_oid_data);
579 goto out;
580 }
581 require(CFEqual(pki_status, CFSTR("0")), out);
582 }
583
584 // can we decode the request?
585 encrypted_content = CFDataCreateMutable(kCFAllocatorDefault, 0);
586 require_noerr(SecCMSDecryptEnvelopedData(signed_content, encrypted_content, &recipient), out);
587 require(recipient, out);
588 // verify recipient belongs with our private key
589
590 // verify CSR:
591 require(certificates = SecCMSCertificatesOnlyMessageCopyCertificates(encrypted_content), out);
592
593 // recipient is either our temporary self-signed cert or the old cert we just used
594 // to recertify. if we have new certificates and have stored them successfully we
595 // can now get rid of the cert.
596 /* XXX/cs
597 This should move outside of thise function when we force a signer
598 to be passed in */
599 CFDictionaryRef cert_delete = CFDictionaryCreate(NULL,
600 (const void **)&kSecValueRef, (const void **)&recipient, 1, NULL, NULL);
601 require_noerr_action(SecItemDelete(cert_delete), out,
602 CFReleaseSafe(cert_delete));
603 CFReleaseSafe(cert_delete);
604
605 out:
606 CFReleaseSafe(ca_public_key);
607 CFReleaseSafe(cert);
608 CFReleaseSafe(cert_msg);
609 CFReleaseSafe(enc_cert_msg);
610 CFReleaseSafe(trust);
611 CFReleaseSafe(policy);
612 CFReleaseSafe(signed_content);
613 CFReleaseSafe(encrypted_content);
614 CFReleaseSafe(recipient);
615 CFReleaseSafe(msg_type);
616 CFReleaseSafe(pki_status);
617 CFReleaseSafe(attributes);
618
619 return certificates;
620 }
621
622 OSStatus SecSCEPValidateCACertMessage(CFArrayRef certs,
623 CFDataRef ca_fingerprint,
624 SecCertificateRef *ca_certificate,
625 SecCertificateRef *ra_signing_certificate,
626 SecCertificateRef *ra_encryption_certificate)
627 {
628 OSStatus status = errSecParam;
629 SecCertificateRef _ca_certificate = NULL, _ra_signing_certificate = NULL,
630 _ra_encryption_certificate = NULL, _ra_certificate = NULL;
631 CFDataRef ca_cert_data = NULL;
632 CFDataRef ca_hash_cfdata = NULL;
633 CFIndex j, count = CFArrayGetCount(certs);
634 CFMutableArrayRef chain = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
635 SecPolicyRef policy = SecPolicyCreateBasicX509();
636 SecTrustRef trust = NULL;
637 require(chain, out);
638 for (j=0; j<count; j++) {
639 const void *candidate_leaf = CFArrayGetValueAtIndex(certs, j);
640 CFArrayRemoveAllValues(chain);
641 CFArraySetValueAtIndex(chain, 0, candidate_leaf);
642 CFArrayAppendArray(chain, certs, CFRangeMake(0, count));
643 CFArrayRemoveValueAtIndex(chain, 1 + j);
644 require_noerr(SecTrustCreateWithCertificates(chain,
645 policy, &trust), out);
646 SecTrustResultType trust_result;
647 SecTrustEvaluate(trust, &trust_result);
648 CFIndex chain_count = SecTrustGetCertificateCount(trust);
649 secdebug("scep", "candidate leaf: %@ forms chain of length %" PRIdCFIndex, candidate_leaf, chain_count);
650 if (chain_count > 1) {
651 SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
652 SecCertificateRef ca_leaf = SecTrustGetCertificateAtIndex(trust, chain_count - 1);
653 if (!_ca_certificate) {
654 if (ca_fingerprint) {
655 secdebug("scep", "checking ca %@ against fingerprint %@", ca_leaf, ca_fingerprint);
656 uint8_t ca_hash[CC_SHA1_DIGEST_LENGTH]; /*max(md5,sha-1)*/
657 ca_cert_data = SecCertificateCopyData(ca_leaf);
658 require(ca_cert_data, out);
659 size_t ca_data_len = CFDataGetLength(ca_cert_data);
660 size_t ca_fingerprint_len = CFDataGetLength(ca_fingerprint);
661 const uint8_t *ca_data = CFDataGetBytePtr(ca_cert_data);
662 require(ca_data_len && ca_data, out);
663 require(ca_data_len<UINT32_MAX, out);
664 switch (ca_fingerprint_len) {
665 case CC_MD5_DIGEST_LENGTH:
666 CC_MD5(ca_data, (CC_LONG)ca_data_len, ca_hash);
667 break;
668
669 case CC_SHA1_DIGEST_LENGTH:
670 CCDigest(kCCDigestSHA1, ca_data, (CC_LONG)ca_data_len, ca_hash);
671 break;
672
673 default:
674 goto out;
675 }
676 CFReleaseNull(ca_cert_data);
677 ca_hash_cfdata = CFDataCreate(kCFAllocatorDefault, ca_hash, ca_fingerprint_len);
678 require(ca_hash_cfdata, out);
679 require(CFEqual(ca_fingerprint, ca_hash_cfdata), out);
680 CFReleaseNull(ca_hash_cfdata);
681 }
682 _ca_certificate = ca_leaf;
683 CFRetain(ca_leaf);
684 } else {
685 // if ca_certificate is already set, this should be the same
686 require(CFEqual(_ca_certificate, ca_leaf), out);
687 }
688
689 // is leaf allowed to sign and/or encrypt?
690 SecKeyUsage key_usage = SecCertificateGetKeyUsage(leaf);
691 bool can_sign = (key_usage & kSecKeyUsageDigitalSignature);
692 bool can_enc = (key_usage & kSecKeyUsageKeyEncipherment);
693 if (!_ra_certificate && can_sign && can_enc) {
694 _ra_certificate = leaf;
695 CFRetain(leaf);
696 }
697 else if (!_ra_encryption_certificate && !can_sign && can_enc) {
698 _ra_encryption_certificate = leaf;
699 CFRetain(leaf);
700 }
701 else if (!_ra_signing_certificate && !can_enc && can_sign) {
702 _ra_signing_certificate = leaf;
703 CFRetain(leaf);
704 }
705 }
706 if (trust) { CFRelease(trust); trust = NULL; }
707 }
708
709 // we should have both a ca certificate and at least one ra certificate now
710 require(_ca_certificate, out);
711 require(_ra_certificate ||
712 (_ra_signing_certificate && _ra_encryption_certificate), out);
713
714 if (ca_certificate) {
715 *ca_certificate = _ca_certificate;
716 _ca_certificate = NULL;
717 }
718 if (_ra_signing_certificate && _ra_encryption_certificate) {
719 if (ra_signing_certificate) {
720 *ra_signing_certificate = _ra_signing_certificate;
721 _ra_signing_certificate = NULL;
722 }
723 if (ra_encryption_certificate) {
724 *ra_encryption_certificate = _ra_encryption_certificate;
725 _ra_encryption_certificate = NULL;
726 }
727 } else if (_ra_certificate) {
728 if (ra_signing_certificate) {
729 *ra_signing_certificate = _ra_certificate;
730 _ra_certificate = NULL;
731 }
732 }
733
734 status = errSecSuccess;
735
736 out:
737 CFReleaseSafe(_ra_encryption_certificate);
738 CFReleaseSafe(_ra_signing_certificate);
739 CFReleaseSafe(_ra_certificate);
740 CFReleaseSafe(_ca_certificate);
741 CFReleaseSafe(ca_cert_data);
742 CFReleaseSafe(ca_hash_cfdata);
743 CFReleaseSafe(policy);
744 CFReleaseSafe(trust);
745 CFReleaseSafe(chain);
746 return status;
747
748 }
749
750
751 /*!
752 @function SecSCEPGetCertInitial
753 @abstract generate a scep cert initial request, to be presented to
754 a scep server, in case the first request timed out
755 */
756
757 // XXX/cs pass CA/RA certificates as a CFTypeRef: one or more certificates for ca_certificate and recipient
758
759 CF_RETURNS_RETAINED CFDataRef
760 SecSCEPGetCertInitial(SecCertificateRef ca_certificate, CFArrayRef subject, CFDictionaryRef parameters,
761 CFDictionaryRef signed_attrs, SecIdentityRef signer, CFTypeRef recipient)
762 {
763 CFMutableDataRef signed_request = NULL;
764 CFMutableDictionaryRef simple_attr = NULL;
765 CFDataRef pki_message_contents = NULL;
766 CFMutableDataRef enveloped_data = NULL;
767 CFDataRef msgtype_value_data = NULL;
768 CFDataRef msgtype_oid_data = NULL;
769
770 require(signed_attrs, out);
771 require(pki_message_contents = SecGenerateCertificateRequestSubject(ca_certificate, subject), out);
772 require(enveloped_data = CFDataCreateMutable(kCFAllocatorDefault, 0), out);
773 require_noerr(SecCMSCreateEnvelopedData(recipient, parameters, pki_message_contents, enveloped_data), out);
774
775 /* remember transaction id just for reuse */
776 simple_attr = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 3, signed_attrs);
777
778 /* message type: GetCertInitial (20) */
779 require(msgtype_oid_data = scep_oid(messageType), out);
780 require(msgtype_value_data = printable_string_data(sizeof(GetCertInitial) - 1, GetCertInitial), out);
781 CFDictionarySetValue(simple_attr, msgtype_oid_data, msgtype_value_data);
782 CFReleaseNull(msgtype_oid_data);
783 CFReleaseNull(msgtype_value_data);
784
785 /* random sender nonce, to be verified against recipient nonce in reply */
786 generate_sender_nonce(simple_attr);
787 signed_request = CFDataCreateMutable(kCFAllocatorDefault, 0);
788 require_noerr_action(SecCMSCreateSignedData(signer, enveloped_data,
789 parameters, simple_attr, signed_request), out, CFReleaseNull(signed_request));
790
791 out:
792 CFReleaseSafe(simple_attr);
793 CFReleaseSafe(pki_message_contents);
794 CFReleaseSafe(enveloped_data);
795 CFReleaseSafe(msgtype_oid_data);
796 CFReleaseSafe(msgtype_value_data);
797 return signed_request;
798 }
799
800
801 /*
802 +----------------+-----------------+---------------------------+
803 | Attribute | Encoding | Comment |
804 +----------------+-----------------+---------------------------+
805 | transactionID | PrintableString | Decimal value as a string |
806 | messageType | PrintableString | Decimal value as a string |
807 | pkiStatus | PrintableString | Decimal value as a string |
808 | failInfo | PrintableString | Decimal value as a string |
809 | senderNonce | OctetString | |
810 | recipientNonce | OctetString | |
811 +----------------+-----------------+---------------------------+
812
813 4.2.1. transactionID
814
815 The transactionID is an attribute which uniquely identifies a
816 transaction. This attribute is required in all PKI messages.
817
818 Because the enrollment transaction could be interrupted by various
819 errors, including network connection errors or client reboot, the
820 SCEP client generates a transaction identifier by calculating a hash
821 on the public key value for which the enrollment is requested. This
822 retains the same transaction identifier throughout the enrollment
823 transaction, even if the client has rebooted or timed out, and issues
824 a new enrollment request for the same key pair.
825
826 It also provides the way for the CA to uniquely identify a
827 transaction in its database. At the requester side, it generates a
828 transaction identifier which is included in PKCSReq. If the CA
829 returns a response of PENDING, the requester will poll by
830 periodically sending out GetCertInitial with the same transaction
831 identifier until either a response other than PENDING is obtained, or
832 the configured maximum time has elapsed.
833
834 For non-enrollment message (for example GetCert and GetCRL), the
835 transactionID should be a number unique to the client.
836
837
838 4.2.2. messageType
839
840 The messageType attribute specify the type of operation performed by
841 the transaction. This attribute is required in all PKI messages.
842 Currently, the following message types are defined:
843
844 o PKCSReq (19) -- PKCS#10 [RFC2986] certificate request
845
846 o CertRep (3) -- Response to certificate or CRL request
847
848 o GetCertInitial (20) -- Certificate polling in manual enrollment
849
850 o GetCert (21) -- Retrieve a certificate
851
852 o GetCRL (22) -- Retrieve a CRL
853
854 4.2.3. pkiStatus
855
856 All response message will include transaction status information
857 which is defined as pkiStatus attribute:
858
859 o SUCCESS (0) -- request granted
860
861 o FAILURE (2) -- request rejected. This also requires a failInfo
862 attribute to be present, as defined in section 4.2.4.
863
864 o PENDING (3) -- request pending for manual approval
865
866
867 4.2.4. failInfo
868
869 The failInfo attribute will contain one of the following failure
870 reasons:
871
872 o badAlg (0) -- Unrecognized or unsupported algorithm ident
873
874 o badMessageCheck (1) -- integrity check failed
875
876 o badRequest (2) -- transaction not permitted or supported
877
878 o badTime (3) -- Message time field was not sufficiently close to
879 the system time
880
881 o badCertId (4) -- No certificate could be identified matching the
882 provided criteria
883
884 4.2.5. senderNonce and responderNonce
885
886 The attributes of senderNonce and recipientNonce are the 16 byte
887 random numbers generated for each transaction to prevent the replay
888 attack.
889
890 When a requester sends a PKI message to the server, a senderNonce is
891 included in the message. After the server processes the request, it
892 will send back the requester senderNonce as the recipientNonce and
893 generates another nonce as the senderNonce in the response message.
894 Because the proposed PKI protocol is a two-way communication
895 protocol, it is clear that the nonce can only be used by the
896 requester to prevent the replay. The server has to employ extra
897 state related information to prevent a replay attack.
898
899 */