/ OSX / sec / Security / SecServerEncryptionSupport.c
SecServerEncryptionSupport.c
  1  //
  2  //  SecServerEncryptionSupport.c
  3  //  sec
  4  //
  5  //
  6  
  7  #include <TargetConditionals.h>
  8  
  9  #include <AssertMacros.h>
 10  #include <Security/SecServerEncryptionSupport.h>
 11  #include <Security/SecECKeyPriv.h>
 12  
 13  #include <utilities/SecCFError.h>
 14  #include <utilities/SecCFWrappers.h>
 15  
 16  #include <Security/SecKeyInternal.h>
 17  
 18  #include <Security/SecBasePriv.h>
 19  
 20  #include <corecrypto/ccsha2.h>
 21  #include <corecrypto/ccecies.h>
 22  #include <corecrypto/ccaes.h>
 23  #include <corecrypto/ccder.h>
 24  
 25  //
 26  // We assume that SecKey is set up for this to work.
 27  // Specifically ccrng_seckey needs to be initialized
 28  //
 29  // As it happens we work in terms of SecKeys at the
 30  // higher level, so we're good.
 31  //
 32  
 33  const uint32_t kBlobCipherKeySize = CCAES_KEY_SIZE_128;
 34  const uint32_t kBlobMacSize = 16;
 35  
 36  static void InitServerECIES(ccecies_gcm_t ecies, const struct ccmode_gcm *gcm_mode)
 37  {
 38      ccecies_encrypt_gcm_setup(ecies,
 39                                ccsha256_di(),
 40                                ccrng_seckey,
 41                                gcm_mode,
 42                                kBlobCipherKeySize,
 43                                kBlobMacSize,
 44                                ECIES_EXPORT_PUB_STANDARD
 45                                +ECIES_EPH_PUBKEY_IN_SHAREDINFO1
 46                                +ECIES_LEGACY_IV);
 47  }
 48  
 49  //
 50  // Der Encode
 51  //
 52  
 53  //
 54  //    EncryptedPayloadToServerVersion ::= INTEGER {v1(1)}
 55  //
 56  //    EncryptedPayloadToServer ::= SEQUENCE {
 57  //        version EncryptedPayloadToServerVersion DEFAULT v1,
 58  //        ephemeralPublicKey OCTET STRING,
 59  //        GCMEncryptedData OCTET STRING,
 60  //        GCMTag OCTET STRING
 61  //    }
 62  
 63  
 64  enum {
 65      SERVER_BLOB_ENCRYPTED_DATA = 0
 66  };
 67  
 68  static size_t sizeof_implicit_nocopy(ccder_tag implicit_tag, size_t space)
 69  {
 70      return ccder_sizeof(implicit_tag, space);
 71  }
 72  
 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)
 74  {
 75      if (start == NULL)
 76          return NULL;
 77  
 78      return ccder_encode_tl(implicit_tag, size, der,
 79                             (*start = ccder_encode_body_nocopy(size, der, der_end)));
 80  }
 81  
 82  static uint8_t *encode_octect_string_nocopy(size_t size, uint8_t**start, const uint8_t *der, uint8_t *der_end)
 83  {
 84      return encode_implicit_nocopy(CCDER_OCTET_STRING, size, start, der, der_end);
 85  }
 86  
 87  static size_t sizeof_server_blob(size_t public_key_size,
 88                                   size_t ciphertext_size,
 89                                   size_t verifier_size)
 90  {
 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));
 95  }
 96  
 97  
 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)
102  {
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))));
107  }
108  
109  static const uint8_t* decode_octect_string(size_t* size, const uint8_t ** start, const uint8_t *der, const uint8_t* der_end)
110  {
111      if (size == NULL)
112          return NULL;
113  
114      der = ccder_decode_tl(CCDER_OCTET_STRING, size, der, der_end);
115  
116      if (der && start) {
117          *start = der;
118          der += *size;
119      }
120  
121      return der;
122  }
123  
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)
128  {
129      const uint8_t *sequence_end;
130      der = ccder_decode_sequence_tl(&sequence_end, der, der_end);
131  
132      if (der_end != sequence_end)
133          der = NULL;
134  
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);
138  
139      return der;
140  }
141  
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,
146                                                             CFErrorRef *error)
147  {
148      CFMutableDataRef result = NULL;
149      CFMutableDataRef allocated = CFDataCreateMutableWithScratch(kCFAllocatorDefault, sizeof_server_blob(public_key_size, ciphertext_size, verifier_size));
150  
151      require_action_quiet(allocated, fail, SecError(errSecAllocate, error, CFSTR("failed to create data")));
152  
153      uint8_t *der = CFDataGetMutableBytePtr(allocated);
154      uint8_t *der_end = der + CFDataGetLength(allocated);
155  
156      der = encode_empty_server_blob_for(public_key_size, public_key_start,
157                                         ciphertext_size, ciphertext,
158                                         verifier_size, verifier,
159                                         der, der_end);
160  
161      require_action_quiet(der, fail, SecError(errSecParam, error, CFSTR("Encoding failed")));
162  
163      CFRetainAssign(result, allocated);
164  
165  fail:
166      CFReleaseNull(allocated);
167      return result;
168  }
169  
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,
174                                        CFErrorRef *error)
175  {
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);
183  
184      require_action_quiet(der == der_end, fail, SecError(errSecParam, error, CFSTR("Blob failed to decode")));
185  
186      success = true;
187  fail:
188      return success;
189  
190  }
191  
192  static size_t ccec_x963_pub_export_size(ccec_pub_ctx_t key)
193  {
194      return ccec_x963_export_size(0,key);
195  }
196  
197  CFDataRef SecCopyEncryptedToServerKey(SecKeyRef publicKey, CFDataRef dataToEncrypt, CFErrorRef *error)
198  {
199      __block CFDataRef result = NULL;
200  
201  
202      SecECDoWithPubKey(publicKey, error, ^(ccec_pub_ctx_t public_key) {
203          CFMutableDataRef encrypted = NULL;
204  
205          struct ccecies_gcm ecies_encrypt;
206          InitServerECIES(&ecies_encrypt, ccaes_gcm_encrypt_mode());
207  
208          size_t plain_size = CFDataGetLength(dataToEncrypt);
209          size_t encrypted_size = ccecies_encrypt_gcm_ciphertext_size(public_key, &ecies_encrypt, plain_size);
210  
211          CFMutableDataRef encryption_temp = CFDataCreateMutableWithScratch(kCFAllocatorDefault, encrypted_size);
212          require_action_quiet(encryption_temp, errout, SecError(errSecAllocate, error, CFSTR("failed to create data")));
213  
214          uint8_t *encryption_buffer = (uint8_t *) CFDataGetMutableBytePtr(encryption_temp);
215  
216          int encrypt_result = ccecies_encrypt_gcm(public_key,
217                                                   &ecies_encrypt,
218                                                   plain_size, CFDataGetBytePtr(dataToEncrypt),
219                                                   0, NULL,
220                                                   0, NULL,
221                                                   &encrypted_size, encryption_buffer);
222  
223  
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;
229          uint8_t *tag = NULL;
230  
231          require_action_quiet(public_key_size + ciphertext_size + tag_size == encrypted_size, errout, SecError(errSecInternal, error, CFSTR("Allocation mismatch")));
232  
233          encrypted = CreateDataForEncodeEncryptedBlobOf(public_key,
234                                                         public_key_size, &public_key_data,
235                                                         ciphertext_size, &ciphertext,
236                                                         tag_size, &tag,
237                                                         error);
238          require_quiet(encrypted, errout);
239  
240          //
241          // Core crypto SPI a work in progress, until then we copy.
242          //
243  
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);
247  
248          require_action_quiet(encrypt_result == 0, errout, SecError(errSecBadReq, error, CFSTR("ccecies_encrypt_gcm failed %d"), encrypt_result));
249  
250          CFRetainAssign(result, encrypted);
251      errout:
252          CFReleaseSafe(encryption_temp);
253          CFReleaseSafe(encrypted);
254      });
255  
256  
257      return result;
258  }
259  
260  
261  CFDataRef SecCopyDecryptedForServer(SecKeyRef serverFullKey, CFDataRef blob, CFErrorRef* error)
262  {
263      __block CFDataRef result = NULL;
264  
265      SecECDoWithFullKey(serverFullKey, error, ^(ccec_full_ctx_t private_key) {
266          CFMutableDataRef plain = NULL;
267          CFMutableDataRef crypto_buffer = NULL;
268          size_t encrypted_size;
269  
270          size_t plain_size;
271  
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;
280  
281          require_quiet(ParseAndFindEncryptedData(blob,
282                                                  &public_key_size, &public_key_start,
283                                                  &ciphertext_size, &ciphertext,
284                                                  &verifier_size, &verifier,
285                                                  error), errout);
286  
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.
290  
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")));
294  
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);
299  
300  
301          plain_size = ccecies_decrypt_gcm_plaintext_size(private_key, &ecies_decrypt, encrypted_size);
302          plain = CFDataCreateMutableWithScratch(kCFAllocatorDefault, plain_size);
303  
304          int decrypt_result = ccecies_decrypt_gcm(private_key,
305                                                   &ecies_decrypt,
306                                                   encrypted_size, crypto_buffer_ptr,
307                                                   0, NULL,
308                                                   0, NULL,
309                                                   &plain_size, CFDataGetMutableBytePtr(plain));
310  
311          require_action_quiet(decrypt_result == 0, errout, SecError(errSecBadReq, error, CFSTR("ccecies_decrypt_gcm failed %d"), decrypt_result));
312  
313          CFRetainAssign(result, plain);
314          
315      errout:
316          CFReleaseSafe(plain);
317          CFReleaseSafe(crypto_buffer);
318      });
319  
320      return result;
321  }
322  
323  #if TARGET_OS_OSX
324  #include <Security/SecTrustInternal.h>
325  #endif
326  
327  CFDataRef SecCopyEncryptedToServer(SecTrustRef trustedEvaluation, CFDataRef dataToEncrypt, CFErrorRef *error)
328  {
329      CFDataRef result = NULL;
330      SecKeyRef trustKey = SecTrustCopyKey(trustedEvaluation);
331  
332      require_action_quiet(trustKey, fail,
333                           SecError(errSecInteractionNotAllowed, error, CFSTR("Failed to get key out of trust ref, was it evaluated?")));
334  
335  
336      result = SecCopyEncryptedToServerKey(trustKey, dataToEncrypt, error);
337  
338  fail:
339      CFReleaseNull(trustKey);
340      return result;
341  }