2 // SecServerEncryptionSupport.c
7 #include <TargetConditionals.h>
9 #include <AssertMacros.h>
10 #include <Security/SecServerEncryptionSupport.h>
11 #include <Security/SecECKeyPriv.h>
13 #include <utilities/SecCFError.h>
14 #include <utilities/SecCFWrappers.h>
16 #include <Security/SecKeyInternal.h>
18 #include <Security/SecBasePriv.h>
20 #include <corecrypto/ccsha2.h>
21 #include <corecrypto/ccecies.h>
22 #include <corecrypto/ccaes.h>
23 #include <corecrypto/ccder.h>
26 // We assume that SecKey is set up for this to work.
27 // Specifically ccrng_seckey needs to be initialized
29 // As it happens we work in terms of SecKeys at the
30 // higher level, so we're good.
33 const uint32_t kBlobCipherKeySize
= CCAES_KEY_SIZE_128
;
34 const uint32_t kBlobMacSize
= 16;
36 static void InitServerECIES(ccecies_gcm_t ecies
, const struct ccmode_gcm
*gcm_mode
)
38 ccecies_encrypt_gcm_setup(ecies
,
44 ECIES_EXPORT_PUB_STANDARD
+ECIES_EPH_PUBKEY_IN_SHAREDINFO1
);
52 // EncryptedPayloadToServerVersion ::= INTEGER {v1(1)}
54 // EncryptedPayloadToServer ::= SEQUENCE {
55 // version EncryptedPayloadToServerVersion DEFAULT v1,
56 // ephemeralPublicKey OCTET STRING,
57 // GCMEncryptedData OCTET STRING,
58 // GCMTag OCTET STRING
63 SERVER_BLOB_ENCRYPTED_DATA
= 0
66 static size_t sizeof_implicit_nocopy(ccder_tag implicit_tag
, size_t space
)
68 return ccder_sizeof(implicit_tag
, space
);
71 static uint8_t *encode_implicit_nocopy(ccder_tag implicit_tag
, size_t size
, uint8_t**start
, const uint8_t *der
, uint8_t *der_end
)
76 return ccder_encode_tl(implicit_tag
, size
, der
,
77 (*start
= ccder_encode_body_nocopy(size
, der
, der_end
)));
80 static uint8_t *encode_octect_string_nocopy(size_t size
, uint8_t**start
, const uint8_t *der
, uint8_t *der_end
)
82 return encode_implicit_nocopy(CCDER_OCTET_STRING
, size
, start
, der
, der_end
);
85 static size_t sizeof_server_blob(size_t public_key_size
,
86 size_t ciphertext_size
,
89 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
,
90 sizeof_implicit_nocopy(CCDER_OCTET_STRING
, public_key_size
) +
91 sizeof_implicit_nocopy(CCDER_OCTET_STRING
, ciphertext_size
) +
92 sizeof_implicit_nocopy(CCDER_OCTET_STRING
, verifier_size
));
96 static uint8_t* encode_empty_server_blob_for(size_t public_key_size
, uint8_t **public_key_start
,
97 size_t ciphertext_size
, uint8_t **ciphertext
,
98 size_t verifier_size
, uint8_t **verifier
,
99 const uint8_t *der
, uint8_t *der_end
)
101 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
102 encode_octect_string_nocopy(public_key_size
, public_key_start
, der
,
103 encode_octect_string_nocopy(ciphertext_size
, ciphertext
, der
,
104 encode_octect_string_nocopy(verifier_size
, verifier
, der
, der_end
))));
107 static const uint8_t* decode_octect_string(size_t* size
, const uint8_t ** start
, const uint8_t *der
, const uint8_t* der_end
)
112 der
= ccder_decode_tl(CCDER_OCTET_STRING
, size
, der
, der_end
);
122 static const uint8_t* decode_server_blob(size_t *public_key_size
, const uint8_t **public_key_start
,
123 size_t *ciphertext_size
, const uint8_t **ciphertext
,
124 size_t *verifier_size
, const uint8_t **verifier
,
125 CFErrorRef
*error
, const uint8_t *der
, const uint8_t *der_end
)
127 const uint8_t *sequence_end
;
128 der
= ccder_decode_sequence_tl(&sequence_end
, der
, der_end
);
130 if (der_end
!= sequence_end
)
133 der
= decode_octect_string(public_key_size
, public_key_start
, der
, der_end
);
134 der
= decode_octect_string(ciphertext_size
, ciphertext
, der
, der_end
);
135 der
= decode_octect_string(verifier_size
, verifier
, der
, der_end
);
140 static CFMutableDataRef
CreateDataForEncodeEncryptedBlobOf(ccec_pub_ctx_t public_key
,
141 size_t public_key_size
, uint8_t **public_key_start
,
142 size_t ciphertext_size
, uint8_t **ciphertext
,
143 size_t verifier_size
, uint8_t **verifier
,
146 CFMutableDataRef result
= NULL
;
147 CFMutableDataRef allocated
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, sizeof_server_blob(public_key_size
, ciphertext_size
, verifier_size
));
149 require_action_quiet(allocated
, fail
, SecError(errSecAllocate
, error
, CFSTR("failed to create data")));
151 uint8_t *der
= CFDataGetMutableBytePtr(allocated
);
152 uint8_t *der_end
= der
+ CFDataGetLength(allocated
);
154 der
= encode_empty_server_blob_for(public_key_size
, public_key_start
,
155 ciphertext_size
, ciphertext
,
156 verifier_size
, verifier
,
159 require_action_quiet(der
, fail
, SecError(errSecParam
, error
, CFSTR("Encoding failed")));
161 CFRetainAssign(result
, allocated
);
164 CFReleaseNull(allocated
);
168 static bool ParseAndFindEncryptedData(CFDataRef blob
,
169 size_t *public_key_size
, const uint8_t **public_key_start
,
170 size_t *ciphertext_size
, const uint8_t **ciphertext
,
171 size_t *verifier_size
, const uint8_t **verifier
,
174 bool success
= false;
175 const uint8_t *der
= CFDataGetBytePtr(blob
);
176 const uint8_t *der_end
= der
+ CFDataGetLength(blob
);
177 der
= decode_server_blob(public_key_size
, public_key_start
,
178 ciphertext_size
, ciphertext
,
179 verifier_size
, verifier
,
180 error
, der
, der_end
);
182 require_action_quiet(der
== der_end
, fail
, SecError(errSecParam
, error
, CFSTR("Blob failed to decode")));
190 static size_t ccec_x963_pub_export_size(ccec_pub_ctx_t key
)
192 return ccec_x963_export_size(0,(ccec_full_ctx_t
)key
.body
); // We lie since the API is broken.
195 CFDataRef
SecCopyEncryptedToServerKey(SecKeyRef publicKey
, CFDataRef dataToEncrypt
, CFErrorRef
*error
)
197 __block CFDataRef result
= NULL
;
200 SecECDoWithPubKey(publicKey
, error
, ^(ccec_pub_ctx_t public_key
) {
201 CFMutableDataRef encrypted
= NULL
;
203 struct ccecies_gcm ecies_encrypt
;
204 InitServerECIES(&ecies_encrypt
, ccaes_gcm_encrypt_mode());
206 size_t plain_size
= CFDataGetLength(dataToEncrypt
);
207 size_t encrypted_size
= ccecies_encrypt_gcm_ciphertext_size(public_key
, &ecies_encrypt
, plain_size
);
209 CFMutableDataRef encryption_temp
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, encrypted_size
);
210 require_action_quiet(encryption_temp
, errout
, SecError(errSecAllocate
, error
, CFSTR("failed to create data")));
212 uint8_t *encryption_buffer
= (uint8_t *) CFDataGetMutableBytePtr(encryption_temp
);
214 int encrypt_result
= ccecies_encrypt_gcm(public_key
,
216 plain_size
, CFDataGetBytePtr(dataToEncrypt
),
219 &encrypted_size
, encryption_buffer
);
222 size_t public_key_size
= ccec_x963_pub_export_size(public_key
);
223 uint8_t *public_key_data
= NULL
;
224 size_t ciphertext_size
= plain_size
;
225 uint8_t *ciphertext
= NULL
;
226 size_t tag_size
= kBlobMacSize
;
229 require_action_quiet(public_key_size
+ ciphertext_size
+ tag_size
== encrypted_size
, errout
, SecError(errSecInternal
, error
, CFSTR("Allocation mismatch"), encrypt_result
));
231 encrypted
= CreateDataForEncodeEncryptedBlobOf(public_key
,
232 public_key_size
, &public_key_data
,
233 ciphertext_size
, &ciphertext
,
236 require_quiet(encrypted
, errout
);
239 // Core crypto SPI a work in progress, until then we copy.
242 memcpy(public_key_data
, encryption_buffer
, public_key_size
);
243 memcpy(ciphertext
, encryption_buffer
+ public_key_size
, ciphertext_size
);
244 memcpy(tag
, encryption_buffer
+ public_key_size
+ ciphertext_size
, tag_size
);
246 require_action_quiet(encrypt_result
== 0, errout
, SecError(errSecBadReq
, error
, CFSTR("ccecies_encrypt_gcm failed %d"), encrypt_result
));
248 CFRetainAssign(result
, encrypted
);
250 CFReleaseSafe(encryption_temp
);
251 CFReleaseSafe(encrypted
);
259 CFDataRef
SecCopyDecryptedForServer(SecKeyRef serverFullKey
, CFDataRef blob
, CFErrorRef
* error
)
261 __block CFDataRef result
= NULL
;
263 SecECDoWithFullKey(serverFullKey
, error
, ^(ccec_full_ctx_t private_key
) {
264 CFMutableDataRef plain
= NULL
;
265 CFMutableDataRef crypto_buffer
= NULL
;
266 size_t encrypted_size
;
270 struct ccecies_gcm ecies_decrypt
;
271 InitServerECIES(&ecies_decrypt
, ccaes_gcm_decrypt_mode());
272 size_t public_key_size
;
273 const uint8_t *public_key_start
= NULL
;
274 size_t ciphertext_size
;
275 const uint8_t *ciphertext
= NULL
;
276 size_t verifier_size
;
277 const uint8_t *verifier
= NULL
;
279 require_quiet(ParseAndFindEncryptedData(blob
,
280 &public_key_size
, &public_key_start
,
281 &ciphertext_size
, &ciphertext
,
282 &verifier_size
, &verifier
,
285 require_quiet(public_key_start
, errout
); // Silence analyzer, shouldn't ever happen.
286 require_quiet(ciphertext
, errout
); // Silence analyzer, shouldn't ever happen.
287 require_quiet(verifier
, errout
); // Silence analyzer, shouldn't ever happen.
289 encrypted_size
= public_key_size
+ ciphertext_size
+ verifier_size
;
290 crypto_buffer
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, encrypted_size
);
291 require_action_quiet(crypto_buffer
, errout
, SecError(errSecAllocate
, error
, CFSTR("failed to create data")));
293 uint8_t *crypto_buffer_ptr
= CFDataGetMutableBytePtr(crypto_buffer
);
294 memcpy(crypto_buffer_ptr
, public_key_start
, public_key_size
);
295 memcpy(crypto_buffer_ptr
+ public_key_size
, ciphertext
, ciphertext_size
);
296 memcpy(crypto_buffer_ptr
+ public_key_size
+ ciphertext_size
, verifier
, verifier_size
);
299 plain_size
= ccecies_decrypt_gcm_plaintext_size(private_key
, &ecies_decrypt
, encrypted_size
);
300 plain
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, plain_size
);
302 int decrypt_result
= ccecies_decrypt_gcm(private_key
,
304 encrypted_size
, crypto_buffer_ptr
,
307 &plain_size
, CFDataGetMutableBytePtr(plain
));
309 require_action_quiet(decrypt_result
== 0, errout
, SecError(errSecBadReq
, error
, CFSTR("ccecies_decrypt_gcm failed %d"), decrypt_result
));
311 CFRetainAssign(result
, plain
);
314 CFReleaseSafe(plain
);
315 CFReleaseSafe(crypto_buffer
);
321 #if TARGET_OS_MAC && !(TARGET_OS_IPHONE || TARGET_OS_EMBEDDED)
322 #include <Security/SecTrustInternal.h>
325 CFDataRef
SecCopyEncryptedToServer(SecTrustRef trustedEvaluation
, CFDataRef dataToEncrypt
, CFErrorRef
*error
)
327 CFDataRef result
= NULL
;
328 #if TARGET_OS_MAC && !(TARGET_OS_IPHONE || TARGET_OS_EMBEDDED)
329 SecKeyRef trustKey
= SecTrustCopyPublicKey_ios(trustedEvaluation
);
331 SecKeyRef trustKey
= SecTrustCopyPublicKey(trustedEvaluation
);
334 require_action_quiet(trustKey
, fail
,
335 SecError(errSecInteractionNotAllowed
, error
, CFSTR("Failed to get key out of trust ref, was it evaluated?")));
338 result
= SecCopyEncryptedToServerKey(trustKey
, dataToEncrypt
, error
);
341 CFReleaseNull(trustKey
);