2 * SecOTRPublicIdentity.c
3 * libsecurity_libSecOTR
5 * Created by Mitch Adler on 2/9/11.
6 * Copyright 2011 Apple Inc. All rights reserved.
11 #include "SecOTRIdentityPriv.h"
12 #include <utilities/SecCFWrappers.h>
14 #include <AssertMacros.h>
16 #include <CoreFoundation/CFNumber.h>
17 #include <CoreFoundation/CFString.h>
18 #include <CoreFoundation/CFData.h>
20 #include <Security/SecKey.h>
21 #include <Security/SecKeyPriv.h>
23 #include <corecrypto/ccn.h>
24 #include <corecrypto/ccec.h>
25 #include <corecrypto/ccder.h>
27 #import <sys/syslog.h>
29 #include "SecOTRErrors.h"
30 #include <TargetConditionals.h>
32 #include <CommonCrypto/CommonDigest.h>
33 #include <CommonCrypto/CommonDigestSPI.h>
36 * Support for encoding and decoding DH parameter blocks.
37 * Apple form encodes the reciprocal of the prime p.
41 kOTRPIDER_SigningID
= 1,
42 kOTRPIDER_SupportsHashes
=3,
46 // SecOTRPublicIdentity implementation
49 CFGiblisFor(SecOTRPublicIdentity
);
51 static bool sAdvertiseHashes
= false;
53 static CF_RETURNS_RETAINED CFStringRef
SecOTRPublicIdentityCopyDescription(CFTypeRef cf
) {
54 SecOTRPublicIdentityRef requestor
= (SecOTRPublicIdentityRef
)cf
;
55 return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<SecOTRPublicIdentity: %p %02x%02x%02x%02x%02x%02x%02x%02x>"),
57 requestor
->hash
[0], requestor
->hash
[1],
58 requestor
->hash
[2], requestor
->hash
[3],
59 requestor
->hash
[4], requestor
->hash
[5],
60 requestor
->hash
[6], requestor
->hash
[7]);
63 static void SecOTRPublicIdentityDestroy(CFTypeRef cf
) {
64 SecOTRPublicIdentityRef requestor
= (SecOTRPublicIdentityRef
)cf
;
66 CFReleaseNull(requestor
->publicSigningKey
);
69 static bool SecKeyDigestAndVerifyWithError(
70 SecKeyRef key
, /* Public key */
71 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
72 const uint8_t *dataToDigest
, /* signature over this data */
73 size_t dataToDigestLen
,/* length of dataToDigest */
74 uint8_t *sig
, /* signature to verify */
75 size_t sigLen
, /* length of sig */
78 OSStatus status
= SecKeyDigestAndVerify(key
, algId
, dataToDigest
, dataToDigestLen
, sig
, sigLen
);
79 require_noerr(status
, fail
);
82 SecOTRCreateError(secOTRErrorOSError
, status
, CFSTR("Error verifying message. OSStatus in error code."), NULL
, error
);
86 static bool SecOTRPICacheHash(SecOTRPublicIdentityRef pubID
, CFErrorRef
*error
)
90 CFMutableDataRef stream
= CFDataCreateMutable(NULL
, 0);
92 require(SecOTRPIAppendSerialization(pubID
, stream
, error
), fail
);
94 CCDigest(kCCDigestSHA1
, CFDataGetBytePtr(stream
), (CC_LONG
)CFDataGetLength(stream
), pubID
->hash
);
99 CFReleaseSafe(stream
);
103 void SecOTRAdvertiseHashes(bool advertise
) {
104 sAdvertiseHashes
= advertise
;
107 SecOTRPublicIdentityRef
SecOTRPublicIdentityCopyFromPrivate(CFAllocatorRef allocator
, SecOTRFullIdentityRef fullID
, CFErrorRef
*error
)
109 SecOTRPublicIdentityRef result
= CFTypeAllocate(SecOTRPublicIdentity
, struct _SecOTRPublicIdentity
, allocator
);
111 EnsureOTRAlgIDInited();
113 result
->publicSigningKey
= fullID
->publicSigningKey
;
114 CFRetain(result
->publicSigningKey
);
116 require(SecOTRPICacheHash(result
, error
), fail
);
121 CFReleaseSafe(result
);
126 SecOTRPublicIdentityRef
SecOTRPublicIdentityCreateFromSecKeyRef(CFAllocatorRef allocator
, SecKeyRef publicKey
,
128 // TODO - make sure this is an appropriate key type
129 SecOTRPublicIdentityRef result
= CFTypeAllocate(SecOTRPublicIdentity
, struct _SecOTRPublicIdentity
, allocator
);
130 result
->publicSigningKey
= publicKey
;
131 CFRetain(result
->publicSigningKey
);
132 require(SecOTRPICacheHash(result
, error
), fail
);
135 CFRelease(result
->publicSigningKey
);
136 CFReleaseSafe(result
);
140 typedef SecKeyRef (*SecOTRPublicKeyCreateFunction
)(CFAllocatorRef allocator
, const uint8_t** data
, size_t* limit
);
142 static SecKeyRef
SecOTRCreatePublicKeyFrom(const uint8_t* keyData
, size_t keyDataSize
, ccder_tag tagContainingKey
, SecOTRPublicKeyCreateFunction createFunction
)
144 SecKeyRef createdKey
= NULL
;
146 createdKey
= createFunction(kCFAllocatorDefault
, &keyData
, &keyDataSize
);
148 require(createdKey
!= NULL
, fail
);
149 require(keyDataSize
== 0, fail
);
154 CFReleaseSafe(createdKey
);
159 SecOTRPublicIdentityRef
SecOTRPublicIdentityCreateFromBytes(CFAllocatorRef allocator
, const uint8_t**bytes
, size_t* size
, CFErrorRef
*error
)
161 CFErrorRef stackedError
= NULL
;
163 SecOTRPublicIdentityRef newID
= CFTypeAllocate(SecOTRPublicIdentity
, struct _SecOTRPublicIdentity
, allocator
);
165 EnsureOTRAlgIDInited();
167 const uint8_t* fullSequenceEnd
= *bytes
+ *size
;
169 const uint8_t* keyData
= ccder_decode_sequence_tl(&fullSequenceEnd
, *bytes
, fullSequenceEnd
);
170 size_t fullSize
= (size_t)(fullSequenceEnd
- *bytes
);
173 keyData
= ccder_decode_tl(CCDER_CONTEXT_SPECIFIC
| kOTRPIDER_SigningID
, &keyDataSize
, keyData
, fullSequenceEnd
);
174 newID
->publicSigningKey
= SecOTRCreatePublicKeyFrom(keyData
, keyDataSize
, kOTRPIDER_SigningID
, &CreateECPublicKeyFrom
);
175 require(newID
->publicSigningKey
!= NULL
, fail
);
176 keyData
+= keyDataSize
;
178 newID
->wantsHashes
= (NULL
!= ccder_decode_tl(CCDER_CONTEXT_SPECIFIC
| kOTRPIDER_SupportsHashes
, &keyDataSize
, keyData
, fullSequenceEnd
));
180 require(SecOTRPICacheHash(newID
, &stackedError
), fail
);
188 SecOTRCreateError(secOTRErrorLocal
, kSecOTRErrorCreatePublicIdentity
, CFSTR("Error creating public identity from bytes"), stackedError
, error
);
189 CFReleaseSafe(newID
);
193 SecOTRPublicIdentityRef
SecOTRPublicIdentityCreateFromData(CFAllocatorRef allocator
, CFDataRef serializedData
, CFErrorRef
*error
)
195 if (serializedData
== NULL
)
198 size_t length
= (size_t)CFDataGetLength(serializedData
);
199 const uint8_t* bytes
= CFDataGetBytePtr(serializedData
);
200 return SecOTRPublicIdentityCreateFromBytes(allocator
, &bytes
, &length
, error
);
203 bool SecOTRPIEqualToBytes(SecOTRPublicIdentityRef id
, const uint8_t*bytes
, CFIndex size
)
205 CFDataRef dataToMatch
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, bytes
, size
, kCFAllocatorNull
);
206 CFMutableDataRef idStreamed
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
208 SecOTRPIAppendSerialization(id
, idStreamed
, NULL
);
210 bool equal
= CFEqualSafe(dataToMatch
, idStreamed
);
212 CFReleaseNull(dataToMatch
);
213 CFReleaseNull(idStreamed
);
218 bool SecOTRPIEqual(SecOTRPublicIdentityRef left
, SecOTRPublicIdentityRef right
)
223 CFMutableDataRef leftData
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
224 CFMutableDataRef rightData
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
226 SecOTRPIAppendSerialization(left
, leftData
, NULL
);
227 SecOTRPIAppendSerialization(right
, rightData
, NULL
);
229 bool match
= CFEqualSafe(leftData
, rightData
);
231 CFReleaseNull(leftData
);
232 CFReleaseNull(rightData
);
237 size_t SecOTRPISignatureSize(SecOTRPublicIdentityRef publicID
)
239 return SecKeyGetSize(publicID
->publicSigningKey
, kSecKeySignatureSize
);
242 bool SecOTRPIAppendSerialization(SecOTRPublicIdentityRef publicID
, CFMutableDataRef serializeInto
, CFErrorRef
*error
)
244 CFIndex start
= CFDataGetLength(serializeInto
);
246 CFMutableDataRef signingKeySerialized
= NULL
;
248 signingKeySerialized
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
250 uint8_t outputBuffer
[16384];
251 uint8_t* outputBufferEnd
= outputBuffer
+ sizeof(outputBuffer
);
253 uint8_t sendHashes
[1];
254 sendHashes
[0] = 0xFF;
256 require_noerr(appendPublicOctetsAndSize(publicID
->publicSigningKey
, signingKeySerialized
), fail
);
258 uint8_t *result
= ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, outputBufferEnd
, outputBuffer
,
259 ccder_encode_implicit_raw_octet_string(CCDER_CONTEXT_SPECIFIC
| kOTRPIDER_SigningID
, (size_t)CFDataGetLength(signingKeySerialized
), CFDataGetBytePtr(signingKeySerialized
), outputBuffer
,
260 sAdvertiseHashes
? ccder_encode_implicit_raw_octet_string(CCDER_CONTEXT_SPECIFIC
| kOTRPIDER_SupportsHashes
, sizeof(sendHashes
), sendHashes
, outputBuffer
, outputBufferEnd
) : outputBufferEnd
));
262 CFDataAppendBytes(serializeInto
, result
, outputBufferEnd
- result
);
264 CFReleaseSafe(signingKeySerialized
);
269 CFReleaseSafe(signingKeySerialized
);
271 CFDataSetLength(serializeInto
, start
);
273 SecOTRCreateError(secOTRErrorLocal
, kSecOTRErrorCreatePublicBytes
, CFSTR("Unable to create public key bytes"), NULL
, error
);
277 static const uint8_t *mp_decode_forced_uint(cc_size n
, cc_unit
*r
, const uint8_t *der
, const uint8_t *der_end
) {
279 der
= ccder_decode_tl(CCDER_INTEGER
, &len
, der
, der_end
);
280 if (der
&& ccn_read_uint(n
, r
, len
, der
) >= 0)
286 static void SecOTRPIRecreateSignature(const uint8_t *oldSignature
, size_t oldSignatureSize
, uint8_t **newSignature
, size_t *newSignatureSize
)
288 cc_unit r
[ccec_cp_n(ccec_cp_256())], s
[ccec_cp_n(ccec_cp_256())];
289 cc_size n
= ccec_cp_n(ccec_cp_256());
291 const uint8_t *oldSignatureEnd
= oldSignature
+ oldSignatureSize
;
293 oldSignature
= ccder_decode_sequence_tl(&oldSignatureEnd
, oldSignature
, oldSignatureEnd
);
294 oldSignature
= mp_decode_forced_uint(n
, r
, oldSignature
, oldSignatureEnd
);
295 oldSignature
= mp_decode_forced_uint(n
, s
, oldSignature
, oldSignatureEnd
);
297 const uint8_t *outputPointer
= *newSignature
;
298 uint8_t *outputEndPointer
= *newSignature
+ *newSignatureSize
;
300 *newSignature
= ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, outputEndPointer
, outputPointer
, ccder_encode_integer(n
, r
, outputPointer
, ccder_encode_integer(n
, s
, outputPointer
, outputEndPointer
)));
301 long newSigSize
= outputEndPointer
- *newSignature
;
302 *newSignatureSize
= (newSigSize
>= 0) ? (size_t)newSigSize
: 0;
305 bool SecOTRPIVerifySignature(SecOTRPublicIdentityRef publicID
,
306 const uint8_t *dataToHash
, size_t amountToHash
,
307 const uint8_t *signatureStart
, size_t signatureSize
, CFErrorRef
*error
)
309 require(signatureSize
> 0, fail
);
310 require(*signatureStart
== signatureSize
- 1, fail
);
314 require(SecKeyDigestAndVerifyWithError(publicID
->publicSigningKey
, kOTRSignatureAlgIDPtr
,
315 dataToHash
, amountToHash
,
316 (uint8_t*)signatureStart
, signatureSize
, NULL
), fail
);
319 // Workaround some type of compiler bug that won't recognize uint8_t after a label
322 uint8_t replacementSignature
[signatureSize
+ 3];
323 size_t replacementSignatureLen
= sizeof(replacementSignature
);
324 uint8_t *replacementSignaturePtr
= replacementSignature
;
326 SecOTRPIRecreateSignature(signatureStart
, signatureSize
, &replacementSignaturePtr
, &replacementSignatureLen
);
328 require_action(replacementSignaturePtr
, fail2
, SecOTRCreateError(secOTRErrorLocal
, kSecOTRErrorSignatureDidNotRecreate
, CFSTR("Unable to recreate signature blob."), NULL
, error
));
330 require(SecKeyDigestAndVerifyWithError(publicID
->publicSigningKey
, kOTRSignatureAlgIDPtr
,
331 dataToHash
, amountToHash
,
332 replacementSignaturePtr
, replacementSignatureLen
, error
), fail2
);
339 void SecOTRPICopyHash(SecOTRPublicIdentityRef publicID
, uint8_t hash
[kMPIDHashSize
])
341 memcpy(hash
, publicID
->hash
, kMPIDHashSize
);
344 void SecOTRPIAppendHash(SecOTRPublicIdentityRef publicID
, CFMutableDataRef appendTo
)
346 CFDataAppendBytes(appendTo
, publicID
->hash
, sizeof(publicID
->hash
));
349 bool SecOTRPICompareHash(SecOTRPublicIdentityRef publicID
, const uint8_t hash
[kMPIDHashSize
])
351 return 0 == memcmp(hash
, publicID
->hash
, kMPIDHashSize
);