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