1/* 2 * Copyright (c) 2009-2010,2013-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/* 25 * spc.c - Security 26 * 27 * 28 */ 29 30#include <TargetConditionals.h> 31#if TARGET_OS_EMBEDDED 32 33#include "SecurityCommands.h" 34 35#include <CoreFoundation/CoreFoundation.h> 36#include <AssertMacros.h> 37#include <TargetConditionals.h> 38#include <CFNetwork/CFNetwork.h> 39 40extern const CFStringRef kCFStreamPropertySSLPeerTrust; 41#include <Security/SecTrust.h> 42#include <Security/SecCertificate.h> 43#include <Security/SecCertificatePriv.h> 44#include <Security/SecImportExport.h> 45#include <Security/SecPolicy.h> 46#include <Security/SecIdentity.h> 47#include <Security/SecIdentityPriv.h> 48#include <Security/SecRSAKey.h> 49#include <Security/SecSCEP.h> 50#include <Security/SecCMS.h> 51#include <Security/SecItem.h> 52#include <Security/SecInternal.h> 53#include <utilities/array_size.h> 54#include <err.h> 55#include <stdio.h> 56#include <getopt.h> 57 58//static char *scep_url = "https://localhost:2000/cgi-bin/pkiclient.exe"; 59static char *user = "webuser"; 60static char *pass = "webpassowrd"; 61static int debug = 0; 62 63#define BUFSIZE 1024 64 65unsigned char device_cert_der[] = { 66 0x30, 0x82, 0x02, 0xdf, 0x30, 0x82, 0x02, 0x48, 0xa0, 0x03, 0x02, 0x01, 67 0x02, 0x02, 0x0a, 0x01, 0x5c, 0x0a, 0x2f, 0xfd, 0x20, 0x02, 0x00, 0xe6, 68 0x27, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 69 0x01, 0x0b, 0x05, 0x00, 0x30, 0x5a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 70 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 71 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 72 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 73 0x0b, 0x13, 0x0c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x69, 0x50, 0x68, 74 0x6f, 0x6e, 0x65, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 75 0x13, 0x16, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x69, 0x50, 0x68, 0x6f, 76 0x6e, 0x65, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x43, 0x41, 77 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x31, 0x32, 0x31, 0x32, 0x32, 0x33, 78 0x30, 0x33, 0x35, 0x36, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x31, 0x32, 0x31, 79 0x32, 0x32, 0x33, 0x30, 0x33, 0x35, 0x36, 0x5a, 0x30, 0x81, 0x87, 0x31, 80 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x28, 0x66, 0x31, 81 0x66, 0x35, 0x30, 0x66, 0x38, 0x31, 0x32, 0x32, 0x66, 0x62, 0x31, 0x30, 82 0x31, 0x34, 0x36, 0x66, 0x36, 0x35, 0x65, 0x39, 0x30, 0x33, 0x38, 0x30, 83 0x31, 0x37, 0x36, 0x33, 0x34, 0x32, 0x61, 0x64, 0x64, 0x36, 0x61, 0x38, 84 0x35, 0x63, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 85 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 86 0x13, 0x02, 0x43, 0x41, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 87 0x07, 0x13, 0x09, 0x43, 0x75, 0x70, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x6f, 88 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x41, 89 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0f, 0x30, 90 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x06, 0x69, 0x50, 0x68, 0x6f, 91 0x6e, 0x65, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 92 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 93 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xba, 0xc5, 0x2a, 0x7b, 0xb3, 94 0x29, 0x21, 0x8d, 0xbd, 0x01, 0x12, 0xff, 0x0b, 0xf6, 0x14, 0x66, 0x15, 95 0x7b, 0x99, 0xf8, 0x1e, 0x08, 0x46, 0x40, 0xd7, 0x48, 0x57, 0xf0, 0x9c, 96 0x08, 0xac, 0xbc, 0x93, 0xc3, 0xd8, 0x81, 0xd8, 0x52, 0xd7, 0x9e, 0x9b, 97 0x3e, 0x65, 0xef, 0x98, 0x8d, 0x93, 0x2e, 0x79, 0x58, 0x22, 0x98, 0xe2, 98 0xd9, 0x2f, 0x84, 0x6d, 0xf0, 0x50, 0xc6, 0xba, 0x52, 0x28, 0x29, 0xf1, 99 0x83, 0x4c, 0xad, 0xdd, 0x5a, 0x7a, 0xab, 0xd2, 0x74, 0xb2, 0x1d, 0xc1, 100 0xa9, 0xe4, 0x87, 0xbd, 0xa0, 0x94, 0x0e, 0x50, 0xa7, 0xc7, 0xf1, 0x0d, 101 0xda, 0x0c, 0x36, 0x94, 0xf4, 0x2c, 0xb8, 0x76, 0xc7, 0x7b, 0x32, 0x87, 102 0x23, 0x70, 0x9f, 0x3f, 0x19, 0xeb, 0xc3, 0xb5, 0x3a, 0x6e, 0xec, 0xa7, 103 0x9c, 0xb4, 0xdb, 0xe7, 0x6e, 0x6d, 0x5e, 0x3c, 0x14, 0xa1, 0xa6, 0xfb, 104 0x50, 0xfb, 0x17, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x7e, 0x30, 0x7c, 105 0x30, 0x1b, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x14, 0xb2, 0xfe, 0x21, 106 0x23, 0x44, 0x86, 0x95, 0x6a, 0x79, 0xd5, 0x81, 0x26, 0x8e, 0x73, 0x10, 107 0xd8, 0xa7, 0x4c, 0x8e, 0x74, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 108 0x04, 0x16, 0x04, 0x14, 0x33, 0x2f, 0xbd, 0x38, 0x86, 0xbc, 0xb0, 0xb2, 109 0x6a, 0xd3, 0x86, 0xca, 0x92, 0x7c, 0x0a, 0x6d, 0x55, 0xab, 0x34, 0x81, 110 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 111 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 112 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x20, 0x06, 0x03, 0x55, 0x1d, 113 0x25, 0x01, 0x01, 0xff, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 114 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 115 0x05, 0x07, 0x03, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 116 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0xe2, 117 0x0c, 0x37, 0x3e, 0x5f, 0x96, 0x10, 0x0d, 0xea, 0xa5, 0x15, 0x8f, 0xa2, 118 0x5b, 0x01, 0xe0, 0x1f, 0x15, 0x11, 0x42, 0x4b, 0x9e, 0x4b, 0x93, 0x90, 119 0x56, 0x4f, 0x4f, 0xbb, 0xc7, 0x32, 0x74, 0xfc, 0xbd, 0x1c, 0xcc, 0x06, 120 0x9f, 0xbb, 0x0b, 0x11, 0xa4, 0x8b, 0xa0, 0x52, 0x59, 0x94, 0xef, 0x87, 121 0x0c, 0xb1, 0xa8, 0xe0, 0x85, 0x96, 0xe1, 0x1b, 0x8b, 0x56, 0x12, 0x4d, 122 0x94, 0xd6, 0xa5, 0x52, 0x7f, 0x65, 0xf3, 0x21, 0x1f, 0xaa, 0x07, 0x8c, 123 0xaf, 0x69, 0xfa, 0x47, 0xbe, 0x3b, 0x74, 0x1a, 0x7c, 0xa6, 0x25, 0x63, 124 0x18, 0x5f, 0x0d, 0xda, 0xc4, 0x58, 0x01, 0xbc, 0xf2, 0x6d, 0x2d, 0xc1, 125 0x68, 0x3e, 0xa1, 0x2c, 0x59, 0x03, 0x3e, 0xa3, 0x13, 0x1b, 0xd9, 0x42, 126 0x28, 0x1e, 0x6c, 0x7f, 0x7f, 0x9d, 0x29, 0xf6, 0x43, 0x84, 0xe7, 0x60, 127 0xe3, 0x6f, 0x6a, 0x8a, 0x9f, 0x1d, 0x70 128}; 129unsigned int device_cert_der_len = 739; 130 131unsigned char device_key[] = { 132 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xba, 133 0xc5, 0x2a, 0x7b, 0xb3, 0x29, 0x21, 0x8d, 0xbd, 0x01, 0x12, 0xff, 0x0b, 134 0xf6, 0x14, 0x66, 0x15, 0x7b, 0x99, 0xf8, 0x1e, 0x08, 0x46, 0x40, 0xd7, 135 0x48, 0x57, 0xf0, 0x9c, 0x08, 0xac, 0xbc, 0x93, 0xc3, 0xd8, 0x81, 0xd8, 136 0x52, 0xd7, 0x9e, 0x9b, 0x3e, 0x65, 0xef, 0x98, 0x8d, 0x93, 0x2e, 0x79, 137 0x58, 0x22, 0x98, 0xe2, 0xd9, 0x2f, 0x84, 0x6d, 0xf0, 0x50, 0xc6, 0xba, 138 0x52, 0x28, 0x29, 0xf1, 0x83, 0x4c, 0xad, 0xdd, 0x5a, 0x7a, 0xab, 0xd2, 139 0x74, 0xb2, 0x1d, 0xc1, 0xa9, 0xe4, 0x87, 0xbd, 0xa0, 0x94, 0x0e, 0x50, 140 0xa7, 0xc7, 0xf1, 0x0d, 0xda, 0x0c, 0x36, 0x94, 0xf4, 0x2c, 0xb8, 0x76, 141 0xc7, 0x7b, 0x32, 0x87, 0x23, 0x70, 0x9f, 0x3f, 0x19, 0xeb, 0xc3, 0xb5, 142 0x3a, 0x6e, 0xec, 0xa7, 0x9c, 0xb4, 0xdb, 0xe7, 0x6e, 0x6d, 0x5e, 0x3c, 143 0x14, 0xa1, 0xa6, 0xfb, 0x50, 0xfb, 0x17, 0x02, 0x03, 0x01, 0x00, 0x01, 144 0x02, 0x81, 0x80, 0x47, 0x9e, 0x91, 0xc2, 0xeb, 0x99, 0xeb, 0x26, 0xfa, 145 0x02, 0x2e, 0x71, 0xa4, 0xf9, 0x91, 0x2a, 0xf0, 0x33, 0xfc, 0x7f, 0xdb, 146 0xac, 0x5a, 0x9c, 0x44, 0xb1, 0x96, 0x1f, 0x4b, 0x06, 0x3c, 0x8e, 0xf7, 147 0xae, 0xd3, 0x18, 0x3f, 0x86, 0xcc, 0xee, 0x22, 0x23, 0xd4, 0x5d, 0x03, 148 0x47, 0xce, 0xd7, 0xb4, 0x6a, 0x6a, 0xa1, 0xeb, 0xe3, 0x52, 0xc8, 0x5a, 149 0x8c, 0x1b, 0xbd, 0x88, 0xf7, 0x36, 0x34, 0xd2, 0xfe, 0x6b, 0x75, 0x9c, 150 0xa4, 0x97, 0x2f, 0xeb, 0xa8, 0xec, 0x48, 0xb7, 0xe7, 0x53, 0x8f, 0xf1, 151 0x39, 0xca, 0xf8, 0xd2, 0xee, 0x34, 0xdc, 0x10, 0x99, 0x6f, 0xfd, 0x83, 152 0x21, 0xa9, 0xe0, 0xe9, 0x0c, 0x4e, 0x4e, 0x62, 0x5f, 0x9f, 0x0f, 0x05, 153 0xcd, 0xf4, 0x2b, 0x08, 0x06, 0x93, 0x55, 0x76, 0xaf, 0x63, 0x77, 0x80, 154 0x3e, 0xd5, 0xf2, 0xe0, 0x58, 0x7f, 0x3c, 0x41, 0x88, 0x4b, 0xc1, 0x02, 155 0x41, 0x01, 0x84, 0xfc, 0xa9, 0x26, 0x74, 0xe7, 0x4e, 0xe4, 0x39, 0xc4, 156 0x8f, 0x81, 0xe8, 0xc0, 0xd3, 0x6e, 0x01, 0x12, 0x7e, 0x12, 0x2d, 0x61, 157 0xaf, 0xe8, 0x60, 0x65, 0x8b, 0x50, 0x46, 0xdf, 0x02, 0x42, 0xe1, 0xea, 158 0xc1, 0x57, 0x9a, 0x2d, 0x90, 0xdc, 0x10, 0xf1, 0x79, 0xf0, 0xb5, 0x5c, 159 0x89, 0xef, 0x3b, 0xa8, 0x7a, 0x88, 0x3d, 0x54, 0xde, 0x35, 0x9c, 0xc3, 160 0x38, 0x4f, 0x2e, 0xb0, 0x74, 0xf7, 0x02, 0x40, 0x7a, 0xea, 0xc9, 0xfe, 161 0x48, 0xeb, 0x94, 0x20, 0x50, 0x33, 0x9d, 0x4f, 0x6f, 0x7f, 0xb1, 0x0e, 162 0xee, 0x42, 0x1c, 0xae, 0x72, 0x06, 0xb9, 0x9c, 0x80, 0x4a, 0xed, 0x07, 163 0xf8, 0x76, 0x5b, 0x37, 0x81, 0x45, 0x69, 0x09, 0xa5, 0x0d, 0x92, 0xed, 164 0xa8, 0xf0, 0x05, 0x6d, 0xb3, 0xa4, 0xef, 0xfb, 0x1b, 0xf0, 0x89, 0xea, 165 0x80, 0x2d, 0xaf, 0x9d, 0xbe, 0xc0, 0x08, 0x44, 0x58, 0x61, 0xc2, 0xe1, 166 0x02, 0x41, 0x01, 0x31, 0xaf, 0x14, 0x86, 0x82, 0x2c, 0x1c, 0x55, 0x42, 167 0x08, 0x73, 0xf6, 0x55, 0x20, 0xe3, 0x86, 0x79, 0x15, 0x3d, 0x39, 0xaf, 168 0xac, 0x2a, 0xfe, 0xe4, 0x72, 0x28, 0x2e, 0xe7, 0xe2, 0xec, 0xf5, 0xfe, 169 0x6f, 0xeb, 0x8c, 0x9a, 0x3e, 0xe0, 0xad, 0xf0, 0x2a, 0xb3, 0xf7, 0x33, 170 0xaf, 0x0b, 0x3e, 0x93, 0x95, 0x6c, 0xe5, 0x8f, 0xbd, 0x17, 0xfa, 0xed, 171 0xbc, 0x84, 0x8d, 0xc5, 0x55, 0x2a, 0x35, 0x02, 0x40, 0x6b, 0x4e, 0x1f, 172 0x4b, 0x03, 0x63, 0xcd, 0xab, 0xab, 0xf8, 0x73, 0x43, 0x8e, 0xa6, 0x1d, 173 0xef, 0x57, 0xe6, 0x95, 0x5d, 0x61, 0x24, 0x27, 0xd3, 0xcd, 0x58, 0x1b, 174 0xb7, 0x92, 0x9b, 0xd8, 0xa4, 0x0b, 0x11, 0x8a, 0x52, 0x26, 0x2a, 0x44, 175 0x73, 0x7f, 0xc1, 0x12, 0x2c, 0x23, 0xe1, 0x40, 0xb3, 0xaa, 0x3f, 0x82, 176 0x57, 0x1a, 0xd1, 0x47, 0x77, 0xe1, 0xb7, 0x89, 0x40, 0x09, 0x1c, 0x47, 177 0x61, 0x02, 0x41, 0x00, 0xa4, 0x47, 0x7d, 0x98, 0x74, 0x25, 0x95, 0x5a, 178 0xc9, 0xbe, 0x76, 0x66, 0xf8, 0x24, 0xb0, 0x83, 0x49, 0xd2, 0xce, 0x98, 179 0x75, 0x7c, 0xbb, 0xd9, 0x24, 0xe9, 0xc5, 0x53, 0xea, 0xd8, 0xec, 0x94, 180 0x79, 0xbb, 0x4e, 0x96, 0xc6, 0xd6, 0x17, 0x26, 0x77, 0xf3, 0x12, 0x3e, 181 0x15, 0x8e, 0x0c, 0x86, 0xdf, 0xa9, 0xf1, 0x34, 0x9b, 0x49, 0x28, 0x0a, 182 0x95, 0xb5, 0x29, 0x8f, 0x8a, 0x21, 0xff, 0xfc 183}; 184unsigned int device_key_len = 608; 185 186 187static inline CFTypeRef valid_cf_obj(CFTypeRef obj, CFTypeID type) 188{ 189 if (obj && CFGetTypeID(obj) == type) 190 return obj; 191 return NULL; 192} 193 194static inline CFTypeRef dict_get_value_of_type(CFDictionaryRef dict, CFTypeRef key, CFTypeID value_type) 195{ 196 CFTypeRef value = CFDictionaryGetValue(dict, key); 197 return valid_cf_obj(value, value_type); 198} 199 200#include <fcntl.h> 201static inline void write_data(const char * path, CFDataRef data) 202{ 203 int data_file = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0644); 204 write(data_file, CFDataGetBytePtr(data), CFDataGetLength(data)); 205 close(data_file); 206 printf("wrote intermediate result to: %s\n", path); 207} 208 209static void _query_string_apply(const void *key, const void *value, void *context) 210{ 211 CFStringRef escaped_key = 212 CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, 213 (CFStringRef)key, NULL, NULL, kCFStringEncodingUTF8); 214 CFStringRef escaped_value = 215 CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, 216 (CFStringRef)value, NULL, NULL, kCFStringEncodingUTF8); 217 CFMutableStringRef query_string = (CFMutableStringRef)context; 218 219 CFStringRef format; 220 if (CFStringGetLength(query_string) > 1) 221 format = CFSTR("&%@=%@"); 222 else 223 format = CFSTR("%@=%@"); 224 225 CFStringAppendFormat(query_string, NULL, format, escaped_key, escaped_value); 226 CFRelease(escaped_key); 227 CFRelease(escaped_value); 228} 229 230static CF_RETURNS_RETAINED CFURLRef build_url(CFStringRef base, CFDictionaryRef info) 231{ 232 CFURLRef url = NULL, base_url = NULL; 233 CFMutableStringRef query_string = 234 CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("?")); 235 require(query_string, out); 236 if (info) 237 CFDictionaryApplyFunction(info, _query_string_apply, query_string); 238 base_url = CFURLCreateWithString(kCFAllocatorDefault, base, NULL); 239 url = CFURLCreateWithString(kCFAllocatorDefault, query_string, base_url); 240out: 241 CFReleaseSafe(query_string); 242 CFReleaseSafe(base_url); 243 return url; 244} 245 246static CFURLRef scep_url_operation(CFStringRef base, CFStringRef operation, CFStringRef message) 247{ 248 CFURLRef url = NULL; 249 const void *keys[] = { CFSTR("operation"), CFSTR("message") }; 250 const void *values[] = { operation, message }; 251 252 require(operation, out); 253 CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values, message ? 2 : 1, NULL, NULL); 254 url = build_url(base, dict); 255 CFRelease(dict); 256out: 257 return url; 258} 259 260static bool auth_failed(CFHTTPMessageRef request, CFReadStreamRef readStream) 261{ 262 bool isAuthenticationChallenge = false; 263 CFHTTPMessageRef responseHeaders = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader); 264 if (responseHeaders) { 265 // Is the server response an challenge for credentials? 266 isAuthenticationChallenge = (CFHTTPMessageGetResponseStatusCode(responseHeaders) == 401); 267 if (isAuthenticationChallenge) { 268 CFStringRef cf_user = CFStringCreateWithCString(kCFAllocatorDefault, user, kCFStringEncodingUTF8); 269 CFStringRef cf_pass = CFStringCreateWithCString(kCFAllocatorDefault, pass, kCFStringEncodingUTF8); 270 CFHTTPMessageAddAuthentication(request, responseHeaders, cf_user, cf_pass, NULL, false); 271 CFReleaseSafe(cf_pass); 272 CFReleaseSafe(cf_user); 273 } 274 CFRelease(responseHeaders); 275 } 276 return isAuthenticationChallenge; 277} 278 279static CF_RETURNS_RETAINED CFHTTPMessageRef load_request(CFHTTPMessageRef request, CFMutableDataRef data, int retry) 280{ 281 CFHTTPMessageRef result = NULL; 282 283 if (retry < 0) 284 return result; 285 286 CFReadStreamRef rs; 287 rs = CFReadStreamCreateForHTTPRequest(NULL, request); 288 289 const void *keys[] = { 290 kCFStreamSSLValidatesCertificateChain, 291// kCFStreamSSLCertificates, 292 }; 293 //CFArrayRef ident = mit_identity(); 294 const void *values[] = { 295 kCFBooleanFalse, 296// ident, 297 }; 298 299 CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values, 300 array_size(keys), 301 &kCFTypeDictionaryKeyCallBacks, 302 &kCFTypeDictionaryValueCallBacks); 303 CFReadStreamSetProperty(rs, kCFStreamPropertySSLSettings, dict); 304 CFRelease(dict); 305 CFReadStreamSetProperty(rs, kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue); 306 307 if (CFReadStreamOpen(rs)) { 308 do { 309 if (auth_failed(request, rs)) { 310 CFReadStreamClose(rs); 311 CFDataSetLength(data, 0); 312 if (retry) { 313 CFReleaseSafe(rs); 314 return load_request(request, data, retry - 1); 315 } 316 break; 317 } 318 UInt8 buf[BUFSIZE]; 319 CFIndex bytesRead = CFReadStreamRead(rs, buf, BUFSIZE); 320 if (bytesRead > 0) { 321 CFDataAppendBytes(data, buf, bytesRead); 322 } else if (bytesRead == 0) { 323 // Success 324 result = (CFHTTPMessageRef)CFReadStreamCopyProperty(rs, kCFStreamPropertyHTTPResponseHeader); 325 break; 326 } else { 327 // Error 328 break; 329 } 330 } while (true); 331 } else { 332 // Error 333 } 334 335 CFReadStreamClose(rs); 336 CFRelease(rs); 337 if (debug) 338 CFShow(result); 339 return result; 340} 341 342 343static CFDictionaryRef get_encrypted_profile_packet(CFStringRef base_url) 344{ 345#if 1 346 SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, 347 device_cert_der, device_cert_der_len); 348 SecKeyRef key = SecKeyCreateRSAPrivateKey(NULL, 349 device_key, device_key_len, kSecKeyEncodingPkcs1); 350 SecIdentityRef identity = SecIdentityCreate(kCFAllocatorDefault, cert, key); 351 CFRelease(cert); 352 CFRelease(key); 353#else 354 SecIdentityRef identity = lockdown_copy_device_identity(); 355#endif 356 357 CFMutableDictionaryRef machine_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 358 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 359 CFDictionarySetValue(machine_dict, CFSTR("UDID"), CFSTR("f1f50f8122fb10146f65e90380176342add6a85c")); 360 CFStringRef cf_user = CFStringCreateWithCString(kCFAllocatorDefault, user, kCFStringEncodingUTF8); 361 if (cf_user) { 362 CFDictionarySetValue(machine_dict, CFSTR("USERNAME"), cf_user); 363 CFRelease(cf_user); 364 } 365 CFStringRef cf_pass = CFStringCreateWithCString(kCFAllocatorDefault, pass, kCFStringEncodingUTF8); 366 if (cf_pass) { 367 CFDictionarySetValue(machine_dict, CFSTR("PASSWORD"), cf_pass); 368 CFRelease(cf_pass); 369 } 370 CFDataRef machine_dict_data = CFPropertyListCreateXMLData(kCFAllocatorDefault, 371 (CFPropertyListRef)machine_dict); 372 CFMutableDataRef signed_data = CFDataCreateMutable(kCFAllocatorDefault, 0); 373 if (SecCMSSignDataAndAttributes(identity, machine_dict_data, false, signed_data, NULL)) 374 errx(1, "failed to sign data"); 375 CFRelease(identity); 376 CFRelease(machine_dict_data); 377 CFRelease(machine_dict); 378 379 CFURLRef url = build_url(base_url, NULL); 380 CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, 381 CFSTR("POST"), url, kCFHTTPVersion1_1); 382 CFRelease(url); 383 CFHTTPMessageSetBody(request, signed_data); 384 CFRelease(signed_data); 385 CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Content-Type"), 386 CFSTR("application/pkcs7-signature")); 387 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0); 388 CFHTTPMessageRef response = load_request(request, data, 1); 389 CFRelease(request); 390 CFRelease(response); 391 CFErrorRef error = NULL; 392 CFTypeRef result = CFPropertyListCreateWithData(kCFAllocatorDefault, 393 data, kCFPropertyListImmutable, NULL, &error); 394 CFRelease(data); 395 if (error) { 396 CFShow(error); 397 errx(1, "failed to decode encrypted profile response"); 398 CFRelease(error); 399 } 400 if (CFGetTypeID(result) != CFDictionaryGetTypeID()) 401 CFReleaseNull(result); 402 return (CFDictionaryRef)result; 403} 404 405static SecCertificateRef get_ca_cert(CFStringRef scep_base_url, CFStringRef scep_ca_name) 406{ 407 SecCertificateRef cert = NULL; 408 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0); 409 410 CFURLRef url = scep_url_operation(scep_base_url, CFSTR("GetCACert"), scep_ca_name); 411 CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, 412 CFSTR("GET"), url, kCFHTTPVersion1_1); 413 CFHTTPMessageRef result = load_request(request, data, 1); 414 415 if (!result) 416 return NULL; 417 CFStringRef contentTypeValue = CFHTTPMessageCopyHeaderFieldValue(result, CFSTR("Content-Type")); 418// CFHTTPMessageRef response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false); 419// CFHTTPMessageAppendBytes(response, CFDataGetBytePtr(data), CFDataGetLength(data)); 420// CFDataRef bodyValue = CFHTTPMessageCopyBody(response); 421 if (kCFCompareEqualTo == CFStringCompare(CFSTR("application/x-x509-ca-cert"), 422 contentTypeValue, kCFCompareCaseInsensitive)) { 423 // CA only response: application/x-x509-ca-cert 424 cert = SecCertificateCreateWithData(kCFAllocatorDefault, data); 425 if (debug) 426 write_data("/tmp/ca_cert.der", data); 427 } else if (kCFCompareEqualTo == CFStringCompare(CFSTR("application/x-x509-ca-ra-cert"), 428 contentTypeValue, kCFCompareCaseInsensitive)) { 429 // RA/CA response: application/x-x509-ca-ra-cert 430 CFArrayRef cert_array = SecCMSCertificatesOnlyMessageCopyCertificates(data); 431 if (debug) 432 write_data("/tmp/ca_cert_array.der", data); 433 cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, 0); 434 CFRetain(cert); 435 CFRelease(cert_array); 436 } 437 CFRelease(contentTypeValue); 438 CFRelease(data); 439 return cert; 440} 441 442 443static SecIdentityRef perform_scep(CFDictionaryRef scep_dict) 444{ 445 SecIdentityRef identity = NULL; 446 CFDictionaryRef parameters = NULL, csr_parameters = NULL; 447 CFStringRef scep_base_url = NULL, scep_instance_name = NULL, 448 scep_challenge = NULL, scep_subject = NULL, scep_subject_requested = NULL; 449 CFTypeRef scep_key_bitsize = NULL; 450 CFNumberRef key_usage_num = NULL; 451 SecCertificateRef ca_cert = NULL; 452 const void *keygen_keys[] = { kSecAttrKeyType, kSecAttrKeySizeInBits }; 453 const void *keygen_vals[] = { kSecAttrKeyTypeRSA, CFSTR("512") }; 454 455 require(valid_cf_obj(scep_dict,CFDictionaryGetTypeID()), out); 456 require(scep_base_url = 457 dict_get_value_of_type(scep_dict, CFSTR("URL"), CFStringGetTypeID()), out); 458 require(scep_instance_name = 459 dict_get_value_of_type(scep_dict, CFSTR("NAME"), CFStringGetTypeID()), out); 460 require(scep_challenge = 461 dict_get_value_of_type(scep_dict, CFSTR("CHALLENGE"), CFStringGetTypeID()), out); 462 463 scep_subject_requested = 464 dict_get_value_of_type(scep_dict, CFSTR("SUBJECT"), CFStringGetTypeID()); 465 if (scep_subject_requested) { 466 CFArrayRef scep_subject_components = 467 CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, 468 scep_subject_requested, CFSTR("=")); 469 if (CFArrayGetCount(scep_subject_components) == 2) 470 scep_subject = CFArrayGetValueAtIndex(scep_subject_components, 1); 471 } 472 473 scep_key_bitsize = 474 dict_get_value_of_type(scep_dict, CFSTR("KEYSIZE"), CFNumberGetTypeID()); 475 if (!scep_key_bitsize) 476 scep_key_bitsize = 477 dict_get_value_of_type(scep_dict, CFSTR("KEYSIZE"), CFStringGetTypeID()); 478 if (scep_key_bitsize) 479 keygen_vals[1] = scep_key_bitsize; 480 481 parameters = CFDictionaryCreate(kCFAllocatorDefault, 482 keygen_keys, keygen_vals, array_size(keygen_vals), 483 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); 484 485 int key_usage = kSecKeyUsageDigitalSignature | kSecKeyUsageKeyEncipherment; 486 key_usage_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &key_usage); 487 const void *key[] = { kSecCSRChallengePassword, kSecCertificateKeyUsage }; 488 const void *val[] = { scep_challenge ? scep_challenge : CFSTR("magic"), key_usage_num }; 489 csr_parameters = CFDictionaryCreate(kCFAllocatorDefault, key, val, array_size(key), NULL, NULL); 490 491 ca_cert = get_ca_cert(scep_base_url, scep_instance_name ? scep_instance_name : CFSTR("test")); 492 if (!ca_cert) 493 errx(1, "no ca cert returned from scep server."); 494 495 identity = NULL; // enroll_scep(scep_base_url, scep_subject, csr_parameters, parameters, ca_cert); 496 if (!identity) 497 errx(1, "failed to get identity from scep server."); 498 499 500out: 501 CFReleaseSafe(ca_cert); 502 CFReleaseSafe(scep_subject); 503 CFReleaseSafe(key_usage_num); 504 CFReleaseSafe(csr_parameters); 505 CFReleaseSafe(parameters); 506 return identity; 507} 508 509static CFDataRef CF_RETURNS_RETAINED get_profile(CFStringRef url_cfstring, SecIdentityRef identity) 510{ 511 CFURLRef url = NULL; 512 CFHTTPMessageRef request = NULL; 513 SecCertificateRef cert = NULL; 514 CFDataRef cert_data = NULL; 515 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0); 516 CFHTTPMessageRef response = NULL; 517 518 require(url = CFURLCreateWithString(kCFAllocatorDefault, url_cfstring, NULL), out); 519 require(request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, 520 CFSTR("POST"), url, kCFHTTPVersion1_1), out); 521 require_noerr(SecIdentityCopyCertificate(identity, &cert), out); 522 require(cert_data = SecCertificateCopyData(cert), out); 523 CFHTTPMessageSetBody(request, cert_data); 524 // this is technically the wrong mimetype; we'll probably switch to signed data 525 CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Content-Type"), CFSTR("application/x-x509-ca-cert")); 526 response = load_request(request, data, 1); 527 if (debug && data) 528 CFShow(data); 529out: 530 //CFReleaseSafe(response); 531 CFReleaseSafe(request); 532 CFReleaseSafe(url); 533 CFReleaseSafe(cert_data); 534 CFReleaseSafe(cert); 535 CFReleaseSafe(response); 536 return data; 537 538} 539 540static bool validate_profile(CFDataRef profile_plist_data, SecIdentityRef identity) 541{ 542 CFStringRef type = NULL, uuid = NULL; 543 CFMutableDataRef dec_data = NULL; 544 CFDataRef enc_payload = NULL; 545 bool ok = false; 546 CFTypeRef result = CFPropertyListCreateWithData(kCFAllocatorDefault, 547 profile_plist_data, kCFPropertyListImmutable, NULL, NULL); 548 require(valid_cf_obj(result, CFDictionaryGetTypeID()), out); 549 require(type = dict_get_value_of_type(result, CFSTR("PayloadType"), 550 CFStringGetTypeID()), out); 551 require(uuid = dict_get_value_of_type(result, CFSTR("PayloadUUID"), 552 CFStringGetTypeID()), out); 553 enc_payload = dict_get_value_of_type(result, CFSTR("EncryptedPayloadContent"), 554 CFDataGetTypeID()); 555 if (enc_payload) { 556 dec_data = CFDataCreateMutable(kCFAllocatorDefault, 0); 557 require_noerr(SecCMSDecryptEnvelopedData(enc_payload, dec_data, NULL), out); 558 ok = validate_profile(dec_data, identity); 559 } else { 560 ok = true; 561 if (debug) 562 write_data("/tmp/unencrypted_profile.mobileconfig", profile_plist_data); 563 //CFDictionaryRef sub_conf = dict_get_value_of_type(result, CFSTR("PayloadContent"), CFDictionaryGetTypeID()); 564 } 565out: 566 CFReleaseSafe(dec_data); 567 CFReleaseSafe(result); 568 return ok; 569} 570 571#if 0 572static const char *auth = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\ 573<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/\n\ 574PropertyList-1.0.dtd\">\n\ 575<plist version=\"1.0\">\n\ 576<dict>\n\ 577 <key>PayloadContent</key>\n\ 578 <dict>\n\ 579 <key>URL</key>\n\ 580 <string>https://phone.vpn.apple.com/deviceid/</string>\n\ 581 <key>DeviceAttributes</key>\n\ 582 <array>\n\ 583 <string>UDID</string>\n\ 584 <string>VERSION</string>\n\ 585 <string>MAC_ADDRESS_EN0</string>\n\ 586 <string>MAC_ADDRESS_IP0</string>\n\ 587 </array>\n\ 588 <key>CHALLENGE</key>\n\ 589 <string>${USER_COOKIE}</string>\n\ 590 </dict>\n\ 591 <key>PayloadType</key>\n\ 592 <string>Device Identification</string>\n\ 593</dict>\n\ 594</plist>\n"; 595 596static void annotate_machine_info(const void *value, void *context) 597{ 598 CFDictionaryRef machine_dict = NULL; 599 CFStringRef machine_key = NULL; 600 require(machine_dict = (CFDictionaryRef)valid_cf_obj(context, 601 CFDictionaryGetTypeID()), out); 602 require(machine_key = (CFStringRef)valid_cf_obj((CFTypeRef)value, 603 CFStringGetTypeID()), out); 604 if (CFEqual(machine_key, CFSTR("UDID"))) { 605 606 } 607out: 608 return; 609} 610 611static void machine_authentication(CFDataRef req, CFDataRef reply) 612{ 613 CFDataRef machine_auth_request = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, 614 (uint8_t*)auth, strlen(auth), kCFAllocatorNull); 615 CFDictionaryRef auth_dict = NULL; 616 CFMutableDictionaryRef auth_reply_dict = 617 CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 618 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 619 620 if (req) { CFRelease(machine_auth_request); machine_auth_request = req; CFRetain(req); } 621 CFDictionaryRef auth_request_dict = CFPropertyListCreateWithData(kCFAllocatorDefault, 622 machine_auth_request, kCFPropertyListImmutable, NULL, NULL); 623 624 require(auth_reply_dict, out); 625 require(valid_cf_obj(auth_request_dict, CFDictionaryGetTypeID()), out); 626 require(auth_dict = dict_get_value_of_type(auth_request_dict, CFSTR("PayloadContent"), CFDictionaryGetTypeID()), out); 627 CFStringRef challenge = dict_get_value_of_type(auth_dict, CFSTR("CHALLENGE"), CFStringGetTypeID()); 628 if (challenge) 629 CFDictionarySetValue(auth_reply_dict, CFSTR("CHALLENGE"), challenge); 630 CFArrayRef device_info = dict_get_value_of_type(auth_dict, CFSTR("DeviceAttributes"), CFArrayGetTypeID()); 631 if (device_info) 632 CFArrayApplyFunction(device_info, CFRangeMake(0, CFArrayGetCount(device_info)), 633 annotate_machine_info, auth_reply_dict); 634 635 // make copy of reply dict 636out: 637 CFReleaseSafe(machine_auth_request); 638 CFReleaseSafe(auth_request_dict); 639} 640#endif 641 642extern int command_spc(int argc, char * const *argv) 643{ 644 SecIdentityRef identity = NULL; 645 extern char *optarg; 646 extern int optind; 647 int arg; 648 while ((arg = getopt(argc, argv, "du:p:")) != -1) { 649 switch (arg) { 650 case 'd': 651 debug = 1; 652 break; 653 case 'u': 654 user = optarg; 655 break; 656 case 'p': 657 pass = optarg; 658 break; 659 case 'h': 660 default: 661 return 2; 662 } 663 } 664 665 argc -= optind; 666 argv += optind; 667 668#if 0 669 if (argc == 1) { 670 // get plist from argv[0] url 671 } else if (argc == 0) { 672 machine_authentication(NULL, NULL); 673 } else return 2; 674#endif 675 676 if (argc != 1) 677 return 2; 678 679 int result = -1; 680 CFDictionaryRef dict = NULL; 681 CFDictionaryRef scep_config = NULL; 682 CFDictionaryRef payload_content = NULL; 683 CFStringRef profile_url = NULL; 684 CFDataRef profile_data = NULL; 685 CFDataRef profile_plist = NULL; 686 CFStringRef machine_id_url_cfstring = CFStringCreateWithCString(kCFAllocatorDefault, 687 argv[0], kCFStringEncodingUTF8); 688 CFDictionaryRef enroll_packet = 689 get_encrypted_profile_packet(machine_id_url_cfstring); 690 require(enroll_packet && CFGetTypeID(enroll_packet) == CFDictionaryGetTypeID(), out); 691 //require(payload_type(enroll_packet, "Encrypted Profile Service"), out); 692 require(payload_content = dict_get_value_of_type(enroll_packet, 693 CFSTR("PayloadContent"), CFDictionaryGetTypeID()), out); 694 require(scep_config = dict_get_value_of_type(payload_content, 695 CFSTR("SCEP"), CFDictionaryGetTypeID()), out); 696 require(identity = perform_scep(scep_config), out); 697 dict = CFDictionaryCreate(NULL, &kSecValueRef, (const void **)&identity, 1, NULL, NULL); 698 require_noerr(SecItemAdd(dict, NULL), out); 699 CFReleaseNull(dict); 700 require(profile_url = dict_get_value_of_type(payload_content, 701 CFSTR("URL"), CFStringGetTypeID()), out); 702 703 require(profile_data = get_profile(profile_url, identity), out); 704 if (debug) 705 write_data("/tmp/profile.mobileconfig", profile_data); 706 707 require_noerr(SecCMSVerify(profile_data, NULL, NULL, NULL, &profile_plist), out); 708 CFReleaseNull(profile_data); 709 require(profile_plist, out); 710 require(validate_profile(profile_plist, identity), out); 711 712 result = 0; 713out: 714 CFReleaseSafe(dict); 715 CFReleaseSafe(identity); 716 CFReleaseSafe(enroll_packet); 717 CFReleaseSafe(profile_data); 718 CFReleaseSafe(profile_plist); 719 CFReleaseSafe(machine_id_url_cfstring); 720 721 if (result != 0) 722 errx(1, "fail."); 723 return result; 724} 725 726 727#endif // TARGET_OS_EMBEDDED 728