]>
Commit | Line | Data |
---|---|---|
5c19dc3a A |
1 | // |
2 | // SOSPeerInfoDER.c | |
3 | // sec | |
4 | // | |
5 | // Created by Richard Murphy on 2/9/15. | |
6 | // | |
7 | // | |
8 | ||
9 | #include <AssertMacros.h> | |
b54c578e | 10 | #include "keychain/SecureObjectSync/SOSPeerInfoDER.h" |
5c19dc3a A |
11 | |
12 | #include <Security/SecureObjectSync/SOSPeerInfo.h> | |
b54c578e A |
13 | #include "keychain/SecureObjectSync/SOSPeerInfoInternal.h" |
14 | #include "keychain/SecureObjectSync/SOSPeerInfoPriv.h" | |
15 | #include "keychain/SecureObjectSync/SOSPeerInfoV2.h" | |
16 | #include "keychain/SecureObjectSync/SOSInternal.h" | |
5c19dc3a A |
17 | |
18 | #include <utilities/der_plist.h> | |
19 | #include <utilities/der_plist_internal.h> | |
20 | #include <corecrypto/ccder.h> | |
21 | #include <utilities/der_date.h> | |
22 | ||
23 | #include <utilities/SecCFError.h> | |
24 | ||
25 | size_t SOSPeerInfoGetDEREncodedSize(SOSPeerInfoRef peer, CFErrorRef *error) { | |
b54c578e A |
26 | if(!peer) { |
27 | SOSCreateError(kSOSErrorParam, CFSTR("No PeerInfo to encode"), NULL, error); | |
28 | return 0; | |
29 | } | |
5c19dc3a | 30 | size_t plist_size = der_sizeof_plist(peer->description, error); |
b54c578e A |
31 | if (plist_size == 0) { |
32 | SOSCreateError(kSOSErrorParam, CFSTR("No Description to encode"), NULL, error); | |
5c19dc3a | 33 | return 0; |
b54c578e | 34 | } |
5c19dc3a A |
35 | |
36 | size_t signature_size = der_sizeof_data(peer->signature, error); | |
b54c578e A |
37 | if (signature_size == 0) { |
38 | SOSCreateError(kSOSErrorParam, CFSTR("Peer not signed to encode"), NULL, error); | |
5c19dc3a | 39 | return 0; |
b54c578e | 40 | } |
5c19dc3a A |
41 | |
42 | return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, | |
43 | plist_size + signature_size); | |
44 | } | |
45 | ||
46 | uint8_t* SOSPeerInfoEncodeToDER(SOSPeerInfoRef peer, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) { | |
b54c578e A |
47 | if(!peer) { |
48 | SOSCreateError(kSOSErrorParam, CFSTR("No PeerInfo to encode"), NULL, error); | |
49 | return NULL; | |
50 | } | |
5c19dc3a A |
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))); | |
55 | } | |
56 | ||
57 | CFDataRef SOSPeerInfoCopyEncodedData(SOSPeerInfoRef peer, CFAllocatorRef allocator, CFErrorRef *error) { | |
b54c578e A |
58 | if(!peer) { |
59 | SOSCreateError(kSOSErrorParam, CFSTR("No PeerInfo to encode"), NULL, error); | |
60 | return NULL; | |
61 | } | |
fa7225c8 A |
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); | |
64 | }); | |
5c19dc3a A |
65 | } |
66 | ||
67 | ||
68 | ||
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; | |
74 | ||
75 | CFPropertyListRef pl = NULL; | |
76 | ||
77 | pi->gestalt = 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); | |
d64be36e A |
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); | |
5c19dc3a A |
82 | |
83 | if (*der_p == NULL || *der_p != sequence_end) { | |
84 | SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Format of Peer Info DER"), NULL, error); | |
85 | goto fail; | |
86 | } | |
87 | ||
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); | |
93 | goto fail; | |
94 | } | |
95 | ||
96 | pi->description = (CFMutableDictionaryRef) pl; | |
97 | CFRetain(pi->description); | |
98 | CFReleaseNull(pl); | |
99 | ||
100 | CFNumberRef versionNumber = CFDictionaryGetValue(pi->description, sVersionKey); | |
101 | ||
102 | if (versionNumber) { | |
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); | |
108 | goto fail; | |
109 | } | |
110 | CFNumberGetValue(versionNumber, kCFNumberCFIndexType, &pi->version); | |
111 | } | |
112 | ||
113 | CFDictionaryRef gestalt = CFDictionaryGetValue(pi->description, sGestaltKey); | |
114 | ||
115 | if (gestalt == NULL) { | |
116 | SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL, | |
117 | CFSTR("gestalt key missing")); | |
118 | goto fail; | |
119 | } | |
120 | ||
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); | |
126 | goto fail; | |
127 | } | |
128 | ||
129 | pi->gestalt = gestalt; | |
130 | CFRetain(pi->gestalt); | |
131 | ||
fa7225c8 | 132 | pubKey = SOSPeerInfoCopyPubKey(pi, error); |
5c19dc3a A |
133 | require_quiet(pubKey, fail); |
134 | ||
8a50f688 A |
135 | pi->peerID = SOSCopyIDOfKey(pubKey, error); |
136 | require_quiet(pi->peerID, fail); | |
d64be36e A |
137 | pi->spid = CFStringCreateTruncatedCopy(pi->peerID, 8); |
138 | ||
5c19dc3a A |
139 | if(pi->version >= 2) SOSPeerInfoExpandV2Data(pi, error); |
140 | ||
141 | if(!SOSPeerInfoVerify(pi, error)) { | |
142 | SOSCreateErrorWithFormat(kSOSErrorBadSignature, NULL, error, NULL, CFSTR("Signature doesn't validate")); | |
79b9da22 | 143 | if (error) { |
5c19dc3a | 144 | secerror("Can't validate PeerInfo: %@", *error); |
79b9da22 | 145 | } |
5c19dc3a A |
146 | goto fail; |
147 | } | |
148 | ||
149 | CFReleaseNull(pubKey); | |
150 | return pi; | |
151 | ||
152 | fail: | |
153 | CFReleaseNull(pi); | |
154 | CFReleaseNull(pl); | |
155 | CFReleaseNull(pubKey); | |
156 | ||
157 | return NULL; | |
158 | } | |
159 | ||
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); | |
165 | } | |
166 |