5 // Created by Richard Murphy on 2/9/15.
9 #include <AssertMacros.h>
10 #include "keychain/SecureObjectSync/SOSPeerInfoDER.h"
12 #include <Security/SecureObjectSync/SOSPeerInfo.h>
13 #include "keychain/SecureObjectSync/SOSPeerInfoInternal.h"
14 #include "keychain/SecureObjectSync/SOSPeerInfoPriv.h"
15 #include "keychain/SecureObjectSync/SOSPeerInfoV2.h"
16 #include "keychain/SecureObjectSync/SOSInternal.h"
18 #include <utilities/der_plist.h>
19 #include <utilities/der_plist_internal.h>
20 #include <corecrypto/ccder.h>
21 #include <utilities/der_date.h>
23 #include <utilities/SecCFError.h>
25 size_t SOSPeerInfoGetDEREncodedSize(SOSPeerInfoRef peer, CFErrorRef *error) {
27 SOSCreateError(kSOSErrorParam, CFSTR("No PeerInfo to encode"), NULL, error);
30 size_t plist_size = der_sizeof_plist(peer->description, error);
31 if (plist_size == 0) {
32 SOSCreateError(kSOSErrorParam, CFSTR("No Description to encode"), NULL, error);
36 size_t signature_size = der_sizeof_data(peer->signature, error);
37 if (signature_size == 0) {
38 SOSCreateError(kSOSErrorParam, CFSTR("Peer not signed to encode"), NULL, error);
42 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
43 plist_size + signature_size);
46 uint8_t* SOSPeerInfoEncodeToDER(SOSPeerInfoRef peer, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) {
48 SOSCreateError(kSOSErrorParam, CFSTR("No PeerInfo to encode"), NULL, error);
51 if(peer->version >= 2) SOSPeerInfoPackV2Data(peer);
52 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
53 der_encode_plist(peer->description, error, der,
54 der_encode_data(peer->signature, error, der, der_end)));
57 CFDataRef SOSPeerInfoCopyEncodedData(SOSPeerInfoRef peer, CFAllocatorRef allocator, CFErrorRef *error) {
59 SOSCreateError(kSOSErrorParam, CFSTR("No PeerInfo to encode"), NULL, error);
62 return CFDataCreateWithDER(kCFAllocatorDefault, SOSPeerInfoGetDEREncodedSize(peer, error), ^uint8_t*(size_t size, uint8_t *buffer) {
63 return SOSPeerInfoEncodeToDER(peer, error, buffer, (uint8_t *) buffer + size);
69 SOSPeerInfoRef SOSPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
70 const uint8_t** der_p, const uint8_t *der_end) {
71 SOSPeerInfoRef pi = SOSPeerInfoAllocate(allocator);
72 SecKeyRef pubKey = NULL;
73 const uint8_t *sequence_end;
75 CFPropertyListRef pl = NULL;
78 pi->version = 0; // TODO: Encode this in the DER
79 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
80 *der_p = der_decode_plist(allocator, &pl, error, *der_p, sequence_end);
81 *der_p = der_decode_data(allocator, &pi->signature, error, *der_p, sequence_end);
83 if (*der_p == NULL || *der_p != sequence_end) {
84 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Format of Peer Info DER"), NULL, error);
88 if (CFGetTypeID(pl) != CFDictionaryGetTypeID()) {
89 CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(pl));
90 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL,
91 CFSTR("Expected dictionary got %@"), description);
92 CFReleaseSafe(description);
96 pi->description = (CFMutableDictionaryRef) pl;
97 CFRetain(pi->description);
100 CFNumberRef versionNumber = CFDictionaryGetValue(pi->description, sVersionKey);
103 if (CFGetTypeID(versionNumber) != CFNumberGetTypeID()) {
104 CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(versionNumber));
105 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL,
106 CFSTR("Expected (version) number got %@"), description);
107 CFReleaseSafe(description);
110 CFNumberGetValue(versionNumber, kCFNumberCFIndexType, &pi->version);
113 CFDictionaryRef gestalt = CFDictionaryGetValue(pi->description, sGestaltKey);
115 if (gestalt == NULL) {
116 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL,
117 CFSTR("gestalt key missing"));
121 if (!isDictionary(gestalt)) {
122 CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(gestalt));
123 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL,
124 CFSTR("Expected dictionary got %@"), description);
125 CFReleaseSafe(description);
129 pi->gestalt = gestalt;
130 CFRetain(pi->gestalt);
132 pubKey = SOSPeerInfoCopyPubKey(pi, error);
133 require_quiet(pubKey, fail);
135 pi->peerID = SOSCopyIDOfKey(pubKey, error);
136 require_quiet(pi->peerID, fail);
137 pi->spid = CFStringCreateTruncatedCopy(pi->peerID, 8);
139 if(pi->version >= 2) SOSPeerInfoExpandV2Data(pi, error);
141 if(!SOSPeerInfoVerify(pi, error)) {
142 SOSCreateErrorWithFormat(kSOSErrorBadSignature, NULL, error, NULL, CFSTR("Signature doesn't validate"));
144 secerror("Can't validate PeerInfo: %@", *error);
149 CFReleaseNull(pubKey);
155 CFReleaseNull(pubKey);
160 SOSPeerInfoRef SOSPeerInfoCreateFromData(CFAllocatorRef allocator, CFErrorRef* error,
161 CFDataRef peerinfo_data) {
162 const uint8_t *der = CFDataGetBytePtr(peerinfo_data);
163 CFIndex len = CFDataGetLength(peerinfo_data);
164 return SOSPeerInfoCreateFromDER(NULL, error, &der, der+len);