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
45 +ECIES_EPH_PUBKEY_IN_SHAREDINFO1
54 // EncryptedPayloadToServerVersion ::= INTEGER {v1(1)}
56 // EncryptedPayloadToServer ::= SEQUENCE {
57 // version EncryptedPayloadToServerVersion DEFAULT v1,
58 // ephemeralPublicKey OCTET STRING,
59 // GCMEncryptedData OCTET STRING,
60 // GCMTag OCTET STRING
65 SERVER_BLOB_ENCRYPTED_DATA
= 0
68 static size_t sizeof_implicit_nocopy(ccder_tag implicit_tag
, size_t space
)
70 return ccder_sizeof(implicit_tag
, space
);
73 static uint8_t *encode_implicit_nocopy(ccder_tag implicit_tag
, size_t size
, uint8_t**start
, const uint8_t *der
, uint8_t *der_end
)
78 return ccder_encode_tl(implicit_tag
, size
, der
,
79 (*start
= ccder_encode_body_nocopy(size
, der
, der_end
)));
82 static uint8_t *encode_octect_string_nocopy(size_t size
, uint8_t**start
, const uint8_t *der
, uint8_t *der_end
)
84 return encode_implicit_nocopy(CCDER_OCTET_STRING
, size
, start
, der
, der_end
);
87 static size_t sizeof_server_blob(size_t public_key_size
,
88 size_t ciphertext_size
,
91 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
,
92 sizeof_implicit_nocopy(CCDER_OCTET_STRING
, public_key_size
) +
93 sizeof_implicit_nocopy(CCDER_OCTET_STRING
, ciphertext_size
) +
94 sizeof_implicit_nocopy(CCDER_OCTET_STRING
, verifier_size
));
98 static uint8_t* encode_empty_server_blob_for(size_t public_key_size
, uint8_t **public_key_start
,
99 size_t ciphertext_size
, uint8_t **ciphertext
,
100 size_t verifier_size
, uint8_t **verifier
,
101 const uint8_t *der
, uint8_t *der_end
)
103 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
104 encode_octect_string_nocopy(public_key_size
, public_key_start
, der
,
105 encode_octect_string_nocopy(ciphertext_size
, ciphertext
, der
,
106 encode_octect_string_nocopy(verifier_size
, verifier
, der
, der_end
))));
109 static const uint8_t* decode_octect_string(size_t* size
, const uint8_t ** start
, const uint8_t *der
, const uint8_t* der_end
)
114 der
= ccder_decode_tl(CCDER_OCTET_STRING
, size
, der
, der_end
);
124 static const uint8_t* decode_server_blob(size_t *public_key_size
, const uint8_t **public_key_start
,
125 size_t *ciphertext_size
, const uint8_t **ciphertext
,
126 size_t *verifier_size
, const uint8_t **verifier
,
127 CFErrorRef
*error
, const uint8_t *der
, const uint8_t *der_end
)
129 const uint8_t *sequence_end
;
130 der
= ccder_decode_sequence_tl(&sequence_end
, der
, der_end
);
132 if (der_end
!= sequence_end
)
135 der
= decode_octect_string(public_key_size
, public_key_start
, der
, der_end
);
136 der
= decode_octect_string(ciphertext_size
, ciphertext
, der
, der_end
);
137 der
= decode_octect_string(verifier_size
, verifier
, der
, der_end
);
142 static CFMutableDataRef
CreateDataForEncodeEncryptedBlobOf(ccec_pub_ctx_t public_key
,
143 size_t public_key_size
, uint8_t **public_key_start
,
144 size_t ciphertext_size
, uint8_t **ciphertext
,
145 size_t verifier_size
, uint8_t **verifier
,
148 CFMutableDataRef result
= NULL
;
149 CFMutableDataRef allocated
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, sizeof_server_blob(public_key_size
, ciphertext_size
, verifier_size
));
151 require_action_quiet(allocated
, fail
, SecError(errSecAllocate
, error
, CFSTR("failed to create data")));
153 uint8_t *der
= CFDataGetMutableBytePtr(allocated
);
154 uint8_t *der_end
= der
+ CFDataGetLength(allocated
);
156 der
= encode_empty_server_blob_for(public_key_size
, public_key_start
,
157 ciphertext_size
, ciphertext
,
158 verifier_size
, verifier
,
161 require_action_quiet(der
, fail
, SecError(errSecParam
, error
, CFSTR("Encoding failed")));
163 CFRetainAssign(result
, allocated
);
166 CFReleaseNull(allocated
);
170 static bool ParseAndFindEncryptedData(CFDataRef blob
,
171 size_t *public_key_size
, const uint8_t **public_key_start
,
172 size_t *ciphertext_size
, const uint8_t **ciphertext
,
173 size_t *verifier_size
, const uint8_t **verifier
,
176 bool success
= false;
177 const uint8_t *der
= CFDataGetBytePtr(blob
);
178 const uint8_t *der_end
= der
+ CFDataGetLength(blob
);
179 der
= decode_server_blob(public_key_size
, public_key_start
,
180 ciphertext_size
, ciphertext
,
181 verifier_size
, verifier
,
182 error
, der
, der_end
);
184 require_action_quiet(der
== der_end
, fail
, SecError(errSecParam
, error
, CFSTR("Blob failed to decode")));
192 static size_t ccec_x963_pub_export_size(ccec_pub_ctx_t key
)
194 return ccec_x963_export_size(0,key
);
197 CFDataRef
SecCopyEncryptedToServerKey(SecKeyRef publicKey
, CFDataRef dataToEncrypt
, CFErrorRef
*error
)
199 __block CFDataRef result
= NULL
;
202 SecECDoWithPubKey(publicKey
, error
, ^(ccec_pub_ctx_t public_key
) {
203 CFMutableDataRef encrypted
= NULL
;
205 struct ccecies_gcm ecies_encrypt
;
206 InitServerECIES(&ecies_encrypt
, ccaes_gcm_encrypt_mode());
208 size_t plain_size
= CFDataGetLength(dataToEncrypt
);
209 size_t encrypted_size
= ccecies_encrypt_gcm_ciphertext_size(public_key
, &ecies_encrypt
, plain_size
);
211 CFMutableDataRef encryption_temp
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, encrypted_size
);
212 require_action_quiet(encryption_temp
, errout
, SecError(errSecAllocate
, error
, CFSTR("failed to create data")));
214 uint8_t *encryption_buffer
= (uint8_t *) CFDataGetMutableBytePtr(encryption_temp
);
216 int encrypt_result
= ccecies_encrypt_gcm(public_key
,
218 plain_size
, CFDataGetBytePtr(dataToEncrypt
),
221 &encrypted_size
, encryption_buffer
);
224 size_t public_key_size
= ccec_x963_pub_export_size(public_key
);
225 uint8_t *public_key_data
= NULL
;
226 size_t ciphertext_size
= plain_size
;
227 uint8_t *ciphertext
= NULL
;
228 size_t tag_size
= kBlobMacSize
;
231 require_action_quiet(public_key_size
+ ciphertext_size
+ tag_size
== encrypted_size
, errout
, SecError(errSecInternal
, error
, CFSTR("Allocation mismatch")));
233 encrypted
= CreateDataForEncodeEncryptedBlobOf(public_key
,
234 public_key_size
, &public_key_data
,
235 ciphertext_size
, &ciphertext
,
238 require_quiet(encrypted
, errout
);
241 // Core crypto SPI a work in progress, until then we copy.
244 memcpy(public_key_data
, encryption_buffer
, public_key_size
);
245 memcpy(ciphertext
, encryption_buffer
+ public_key_size
, ciphertext_size
);
246 memcpy(tag
, encryption_buffer
+ public_key_size
+ ciphertext_size
, tag_size
);
248 require_action_quiet(encrypt_result
== 0, errout
, SecError(errSecBadReq
, error
, CFSTR("ccecies_encrypt_gcm failed %d"), encrypt_result
));
250 CFRetainAssign(result
, encrypted
);
252 CFReleaseSafe(encryption_temp
);
253 CFReleaseSafe(encrypted
);
261 CFDataRef
SecCopyDecryptedForServer(SecKeyRef serverFullKey
, CFDataRef blob
, CFErrorRef
* error
)
263 __block CFDataRef result
= NULL
;
265 SecECDoWithFullKey(serverFullKey
, error
, ^(ccec_full_ctx_t private_key
) {
266 CFMutableDataRef plain
= NULL
;
267 CFMutableDataRef crypto_buffer
= NULL
;
268 size_t encrypted_size
;
272 struct ccecies_gcm ecies_decrypt
;
273 InitServerECIES(&ecies_decrypt
, ccaes_gcm_decrypt_mode());
274 size_t public_key_size
;
275 const uint8_t *public_key_start
= NULL
;
276 size_t ciphertext_size
;
277 const uint8_t *ciphertext
= NULL
;
278 size_t verifier_size
;
279 const uint8_t *verifier
= NULL
;
281 require_quiet(ParseAndFindEncryptedData(blob
,
282 &public_key_size
, &public_key_start
,
283 &ciphertext_size
, &ciphertext
,
284 &verifier_size
, &verifier
,
287 require_quiet(public_key_start
, errout
); // Silence analyzer, shouldn't ever happen.
288 require_quiet(ciphertext
, errout
); // Silence analyzer, shouldn't ever happen.
289 require_quiet(verifier
, errout
); // Silence analyzer, shouldn't ever happen.
291 encrypted_size
= public_key_size
+ ciphertext_size
+ verifier_size
;
292 crypto_buffer
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, encrypted_size
);
293 require_action_quiet(crypto_buffer
, errout
, SecError(errSecAllocate
, error
, CFSTR("failed to create data")));
295 uint8_t *crypto_buffer_ptr
= CFDataGetMutableBytePtr(crypto_buffer
);
296 memcpy(crypto_buffer_ptr
, public_key_start
, public_key_size
);
297 memcpy(crypto_buffer_ptr
+ public_key_size
, ciphertext
, ciphertext_size
);
298 memcpy(crypto_buffer_ptr
+ public_key_size
+ ciphertext_size
, verifier
, verifier_size
);
301 plain_size
= ccecies_decrypt_gcm_plaintext_size(private_key
, &ecies_decrypt
, encrypted_size
);
302 plain
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, plain_size
);
304 int decrypt_result
= ccecies_decrypt_gcm(private_key
,
306 encrypted_size
, crypto_buffer_ptr
,
309 &plain_size
, CFDataGetMutableBytePtr(plain
));
311 require_action_quiet(decrypt_result
== 0, errout
, SecError(errSecBadReq
, error
, CFSTR("ccecies_decrypt_gcm failed %d"), decrypt_result
));
313 CFRetainAssign(result
, plain
);
316 CFReleaseSafe(plain
);
317 CFReleaseSafe(crypto_buffer
);
324 #include <Security/SecTrustInternal.h>
327 CFDataRef
SecCopyEncryptedToServer(SecTrustRef trustedEvaluation
, CFDataRef dataToEncrypt
, CFErrorRef
*error
)
329 CFDataRef result
= NULL
;
331 SecKeyRef trustKey
= SecTrustCopyPublicKey_ios(trustedEvaluation
);
333 SecKeyRef trustKey
= SecTrustCopyPublicKey(trustedEvaluation
);
336 require_action_quiet(trustKey
, fail
,
337 SecError(errSecInteractionNotAllowed
, error
, CFSTR("Failed to get key out of trust ref, was it evaluated?")));
340 result
= SecCopyEncryptedToServerKey(trustKey
, dataToEncrypt
, error
);
343 CFReleaseNull(trustKey
);