2 * Copyright (c) 2006,2011-2012,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * opensshCoding.h - Encoding and decoding of OpenSSH format public keys.
29 #include "AppleCSPSession.h"
30 #include "AppleCSPContext.h"
31 #include "AppleCSPUtils.h"
32 #include "AppleCSPKeys.h"
33 #include "RSA_DSA_keys.h"
34 #include "opensshCoding.h"
35 #include "cspdebugging.h"
36 #include <CommonCrypto/CommonDigest.h>
37 #include <CommonCrypto/CommonCryptor.h>
38 #include <openssl/rsa_legacy.h>
39 #include <openssl/bn_legacy.h>
40 #include <security_utilities/devrandom.h>
41 #include <utilities/SecCFRelease.h>
43 static const char *authfile_id_string
= "SSH PRIVATE KEY FILE FORMAT 1.1\n";
45 /* default comment on encode if app doesn't provide DescriptiveData */
46 #define OPENSSH1_COMMENT "Encoded by Mac OS X Security.framework"
48 /* from openssh cipher.h */
49 #define SSH_CIPHER_NONE 0 /* no encryption */
50 #define SSH_CIPHER_IDEA 1 /* IDEA CFB */
51 #define SSH_CIPHER_DES 2 /* DES CBC */
52 #define SSH_CIPHER_3DES 3 /* 3DES CBC */
53 #define SSH_CIPHER_BROKEN_TSS 4 /* TRI's Simple Stream encryption CBC */
54 #define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */
55 #define SSH_CIPHER_BLOWFISH 6
56 #define SSH_CIPHER_RESERVED 7
58 #pragma mark --- utilities ---
60 static void appendUint16(
61 CFMutableDataRef cfOut
,
64 UInt8 buf
[sizeof(uint16_t)];
69 CFDataAppendBytes(cfOut
, buf
, sizeof(uint16_t));
72 static uint16_t readUint16(
73 const unsigned char *&cp
, // IN/OUT
74 unsigned &len
) // IN/OUT
83 /* Write BIGNUM, OpenSSH-1 version */
84 static CSSM_RETURN
appendBigNum(
85 CFMutableDataRef cfOut
,
88 /* 16 bits of numbits */
89 unsigned numBits
= BN_num_bits(bn
);
90 appendUint16(cfOut
, numBits
);
92 /* serialize the bytes */
93 int numBytes
= (numBits
+ 7) / 8;
94 unsigned char outBytes
[numBytes
]; // gcc is so cool...
95 int moved
= BN_bn2bin(bn
, outBytes
);
96 if(moved
!= numBytes
) {
97 errorLog0("appendBigNum: BN_bn2bin() screwup\n");
98 return CSSMERR_CSP_INTERNAL_ERROR
;
100 CFDataAppendBytes(cfOut
, (UInt8
*)outBytes
, numBytes
);
104 /* Read BIGNUM, OpenSSH-1 version */
105 static BIGNUM
*readBigNum(
106 const unsigned char *&cp
, // IN/OUT
107 unsigned &remLen
) // IN/OUT
109 if(remLen
< sizeof(uint16_t)) {
110 errorLog0("readBigNum: short record(1)\n");
113 uint16_t numBits
= readUint16(cp
, remLen
);
114 unsigned bytes
= (numBits
+ 7) / 8;
116 errorLog0("readBigNum: short record(2)\n");
119 BIGNUM
*bn
= BN_bin2bn(cp
, bytes
, NULL
);
121 errorLog0("readBigNum: BN_bin2bn error\n");
130 * Calculate d mod{p-1,q-1}
131 * Used when decoding OpenSSH-1 private RSA key.
133 static CSSM_RETURN
rsa_generate_additional_parameters(RSA
*rsa
)
138 if((rsa
->dmq1
= BN_new()) == NULL
) {
139 errorLog0("rsa_generate_additional_parameters: BN_new failed");
140 return CSSMERR_CSP_INTERNAL_ERROR
;
142 if((rsa
->dmp1
= BN_new()) == NULL
) {
143 errorLog0("rsa_generate_additional_parameters: BN_new failed");
144 return CSSMERR_CSP_INTERNAL_ERROR
;
146 if ((aux
= BN_new()) == NULL
) {
147 errorLog0("rsa_generate_additional_parameters: BN_new failed");
148 return CSSMERR_CSP_INTERNAL_ERROR
;
150 if ((ctx
= BN_CTX_new()) == NULL
) {
151 errorLog0("rsa_generate_additional_parameters: BN_CTX_new failed");
153 return CSSMERR_CSP_INTERNAL_ERROR
;
156 BN_sub(aux
, rsa
->q
, BN_value_one());
157 BN_mod(rsa
->dmq1
, rsa
->d
, aux
, ctx
);
159 BN_sub(aux
, rsa
->p
, BN_value_one());
160 BN_mod(rsa
->dmp1
, rsa
->d
, aux
, ctx
);
167 #pragma mark --- encrypt/decrypt ---
170 * Encrypt/decrypt the secret portion of an OpenSSHv1 format RSA private key.
172 static CSSM_RETURN
ssh1DES3Crypt(
173 unsigned char cipher
,
175 const unsigned char *inText
,
177 const uint8
*key
, // MD5(password)
179 unsigned char *outText
, // data RETURNED here, caller mallocs.
180 unsigned *outTextLen
) // RETURNED
183 case SSH_CIPHER_3DES
:
185 case SSH_CIPHER_NONE
:
186 /* cleartext RSA private key, e.g. host key. */
187 memmove(outText
, inText
, inTextLen
);
188 *outTextLen
= inTextLen
;
191 /* who knows how we're going to figure these out */
192 errorLog1("***ssh1DES3Crypt: Unsupported cipher (%u)\n", cipher
);
193 return CSSMERR_CSP_INVALID_KEY
;
196 if(keyLen
!= CC_MD5_DIGEST_LENGTH
) {
197 errorLog0("ssh1DES3Crypt: bad key length\n");
198 return CSSMERR_CSP_INVALID_KEY
;
201 /* three keys from that, like so: */
202 unsigned char k1
[kCCKeySizeDES
];
203 unsigned char k2
[kCCKeySizeDES
];
204 unsigned char k3
[kCCKeySizeDES
];
205 memmove(k1
, key
, kCCKeySizeDES
);
206 memmove(k2
, key
+ kCCKeySizeDES
, kCCKeySizeDES
);
207 memmove(k3
, key
, kCCKeySizeDES
);
220 /* the openssh v1 pseudo triple DES. Each DES pass has its own CBC. */
223 CCCryptorStatus cstat
= CCCrypt(op1_3
, kCCAlgorithmDES
,
228 outText
, inTextLen
, &moved
);
230 /* should never happen */
231 errorLog1("***ssh1DES3Crypt: CCCrypt()(1) returned %u\n", (unsigned)cstat
);
232 return CSSMERR_CSP_INTERNAL_ERROR
;
234 cstat
= CCCrypt(op2
, kCCAlgorithmDES
,
235 0, // no padding - SSH does that itself
239 outText
, inTextLen
, &moved
);
241 errorLog1("***ssh1DES3Crypt: CCCrypt()(2) returned %u\n", (unsigned)cstat
);
242 return CSSMERR_CSP_INTERNAL_ERROR
;
244 cstat
= CCCrypt(op1_3
, kCCAlgorithmDES
,
245 0, // no padding - SSH does that itself
249 outText
, inTextLen
, &moved
);
251 errorLog1("***ssh1DES3Crypt: CCCrypt()(3) returned %u\n", (unsigned)cstat
);
252 return CSSMERR_CSP_INTERNAL_ERROR
;
255 *outTextLen
= (unsigned)moved
;
259 #pragma mark --- DeriveKey ---
262 * Key derivation for OpenSSH1 private key wrap/unwrap.
263 * This is pretty trivial, it's just an MD5() operation. The main
264 * purpose for doing this in a DeriveKey operation is to enable the
265 * use of either Secure Passphrases, obtained by securityd/SecurityAgent,
266 * or app-specified data.
268 void AppleCSPSession::DeriveKey_OpenSSH1(
269 const Context
&context
,
270 CSSM_ALGORITHMS algId
,
271 const CssmData
&Param
, // IV optional, mallocd by app to indicate
273 CSSM_DATA
*keyData
) // mallocd by caller to indicate size - must be
274 // size of MD5 digest!
276 CSSM_DATA pwd
= {0, NULL
};
278 if(keyData
->Length
!= CC_MD5_DIGEST_LENGTH
) {
279 errorLog0("DeriveKey_OpenSSH1: invalid key length\n");
280 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_SIZE
);
283 /* password from either Seed.Param or from base key */
284 CssmCryptoData
*cryptData
=
285 context
.get
<CssmCryptoData
>(CSSM_ATTRIBUTE_SEED
);
286 if((cryptData
!= NULL
) && (cryptData
->Param
.Length
!= 0)) {
287 pwd
= cryptData
->Param
;
290 /* Get secure passphrase from base key */
291 CssmKey
*passKey
= context
.get
<CssmKey
>(CSSM_ATTRIBUTE_KEY
);
292 if (passKey
!= NULL
) {
293 AppleCSPContext::symmetricKeyBits(context
, *this,
294 CSSM_ALGID_SECURE_PASSPHRASE
, CSSM_KEYUSE_DERIVE
,
295 pwd
.Data
, pwd
.Length
);
299 if(pwd
.Data
== NULL
) {
300 errorLog0("DeriveKey_PKCS5_V1_5: null Passphrase\n");
301 CssmError::throwMe(CSSMERR_CSP_INVALID_DATA
);
303 if(pwd
.Length
== 0) {
304 errorLog0("DeriveKey_PKCS5_V1_5: zero length passphrase\n");
305 CssmError::throwMe(CSSMERR_CSP_INVALID_INPUT_POINTER
);
309 CC_MD5(pwd
.Data
, (CC_LONG
)pwd
.Length
, keyData
->Data
);
313 #pragma mark --- Encode/Wrap OpenSSHv1 private key ---
316 * Encode OpenSSHv1 private key, with or without encryption.
317 * This used for generating key blobs of format CSSM_KEYBLOB_RAW_FORMAT_OPENSSH
318 * as well as wrapping keys in format CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1.
320 CSSM_RETURN
encodeOpenSSHv1PrivKey(
322 const uint8
*comment
, /* optional */
324 const uint8
*encryptKey
, /* optional; if present, it's 16 bytes of MD5(password) */
325 CFDataRef
*encodedKey
) /* RETURNED */
327 CFMutableDataRef cfOut
= CFDataCreateMutable(NULL
, 0);
328 CSSM_RETURN ourRtn
= CSSM_OK
;
330 /* ID string including NULL */
331 CFDataAppendBytes(cfOut
, (const UInt8
*)authfile_id_string
, strlen(authfile_id_string
) + 1);
333 /* one byte cipher */
334 UInt8 cipherSpec
= encryptKey
? SSH_CIPHER_3DES
: SSH_CIPHER_NONE
;
335 CFDataAppendBytes(cfOut
, &cipherSpec
, 1);
338 UInt8 spares
[4] = {0};
339 CFDataAppendBytes(cfOut
, spares
, 4);
342 * Clear text public key:
347 uint32_t keybits
= RSA_size(rsa
) * 8;
348 appendUint32(cfOut
, keybits
);
349 appendBigNum(cfOut
, rsa
->n
);
350 appendBigNum(cfOut
, rsa
->e
);
354 * The format appears to require this, or else we wouldn't know
355 * when we've got to the ciphertext on decode.
357 if((comment
== NULL
) || (commentLen
== 0)) {
358 comment
= (const UInt8
*)OPENSSH1_COMMENT
;
359 commentLen
= strlen(OPENSSH1_COMMENT
);
361 appendUint32(cfOut
, commentLen
);
362 CFDataAppendBytes(cfOut
, comment
, commentLen
);
365 * Remainder is encrypted, consisting of
367 * [0-1] -- random bytes
368 * [2-3] -- copy of [01] for passphrase validity checking
369 * buffer_put_bignum(d)
370 * buffer_put_bignum(iqmp)
371 * buffer_put_bignum(q)
372 * buffer_put_bignum(p)
375 CFMutableDataRef ptext
= CFDataCreateMutable(NULL
, 0);
377 /* [0..3] check bytes */
379 DevRandomGenerator rng
= DevRandomGenerator();
380 rng
.random(checkBytes
, 2);
381 checkBytes
[2] = checkBytes
[0];
382 checkBytes
[3] = checkBytes
[1];
383 CFDataAppendBytes(ptext
, checkBytes
, 4);
386 appendBigNum(ptext
, rsa
->d
);
387 appendBigNum(ptext
, rsa
->iqmp
);
388 appendBigNum(ptext
, rsa
->q
);
389 appendBigNum(ptext
, rsa
->p
);
391 /* pad to block boundary */
392 CFIndex ptextLen
= CFDataGetLength(ptext
);
393 unsigned padding
= 0;
394 unsigned rem
= (unsigned)ptextLen
& 0x7;
399 for(unsigned dex
=0; dex
<padding
; dex
++) {
400 CFDataAppendBytes(ptext
, &padByte
, 1);
404 ptextLen
= CFDataGetLength(ptext
);
405 unsigned char *ctext
= (unsigned char*)malloc(ptextLen
);
407 ourRtn
= CSSMERR_CSSM_MEMORY_ERROR
;
412 ourRtn
= ssh1DES3Crypt(cipherSpec
, true,
413 (unsigned char *)CFDataGetBytePtr(ptext
), (unsigned)ptextLen
,
414 encryptKey
, encryptKey
? CC_MD5_DIGEST_LENGTH
: 0,
420 /* appended encrypted portion */
421 CFDataAppendBytes(cfOut
, ctext
, ctextLen
);
425 CFReleaseNull(cfOut
);
427 /* it would be proper to zero out ptext here, but we can't do that to a CFData */
433 void AppleCSPSession::WrapKeyOpenSSH1(
434 CSSM_CC_HANDLE CCHandle
,
435 const Context
&context
,
436 const AccessCredentials
&AccessCred
,
437 BinaryKey
&unwrappedBinKey
,
439 bool allocdRawBlob
, // callee has to free rawBlob
440 const CssmData
*DescriptiveData
,
442 CSSM_PRIVILEGE Privilege
)
445 * The job here is to convert the RSA key in binKey to the OpenSSHv1 private
446 * key format, and drop that into WrappedKey.KeyData (allocated by the session).
448 * This cast throws an exception if the key is not an RSA key, which
449 * would be a major bogon, since our caller verified that the unwrapped key
450 * is a private RSA key.
452 RSABinaryKey
&rPubBinKey
= dynamic_cast<RSABinaryKey
&>(unwrappedBinKey
);
453 RSA
*rsa
= rPubBinKey
.mRsaKey
;
454 CASSERT(rsa
!= NULL
);
457 * Get the raw password bits from the wrapping key.
458 * Our caller verified that the context has a symmetric key; this call
459 * ensures that the key is of algorithm CSSM_ALGID_OPENSSH1.
460 * Key length 0 means no encryption.
462 CSSM_SIZE wrappingKeyLen
= 0;
463 uint8
*wrappingKey
= NULL
;
465 AppleCSPContext::symmetricKeyBits(context
, *this,
466 CSSM_ALGID_OPENSSH1
, CSSM_KEYUSE_WRAP
,
467 wrappingKey
, wrappingKeyLen
);
468 if(wrappingKeyLen
!= CC_MD5_DIGEST_LENGTH
) {
469 errorLog0("AppleCSPSession::WrapKeyOpenSSH1: bad wrapping key length\n");
470 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
473 CFDataRef cfOut
= NULL
;
476 * Optional comment string from DescriptiveData.
478 const UInt8
*comment
= NULL
;
479 unsigned commentLen
= 0;
480 if((DescriptiveData
!= NULL
) && (DescriptiveData
->Length
!= 0)) {
481 comment
= (const UInt8
*)DescriptiveData
->Data
;
482 commentLen
= (unsigned)DescriptiveData
->Length
;
485 /* generate the encrypted blob */
486 CSSM_RETURN crtn
= encodeOpenSSHv1PrivKey(rsa
, comment
, commentLen
, wrappingKey
, &cfOut
);
488 CssmError::throwMe(crtn
);
491 /* allocate key data in session's memory space */
492 CFIndex len
= CFDataGetLength(cfOut
);
493 setUpData(WrappedKey
.KeyData
, len
, normAllocator
);
494 memmove(WrappedKey
.KeyData
.Data
, CFDataGetBytePtr(cfOut
), len
);
495 CFReleaseNull(cfOut
);
497 /* outgoing header */
498 WrappedKey
.KeyHeader
.BlobType
= CSSM_KEYBLOB_WRAPPED
;
499 // OK to be zero or not present
500 WrappedKey
.KeyHeader
.WrapMode
= CSSM_ALGMODE_NONE
;
501 WrappedKey
.KeyHeader
.Format
= CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1
;
504 #pragma mark --- Decode/Unwrap OpenSSHv1 private key ---
507 * Decode OpenSSHv1 private, optionally decrypting the secret portion.
508 * This used for decoding key blobs of format CSSM_KEYBLOB_RAW_FORMAT_OPENSSH
509 * as well as unwrapping keys in format CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1.
511 CSSM_RETURN
decodeOpenSSHv1PrivKey(
512 const unsigned char *encodedKey
,
513 unsigned encodedKeyLen
,
515 const uint8
*decryptKey
, /* optional; if present, it's 16 bytes of MD5(password) */
516 uint8
**comment
, /* optional, mallocd and RETURNED */
517 unsigned *commentLen
) /* RETURNED */
519 unsigned len
= (unsigned)strlen(authfile_id_string
);
520 const unsigned char *cp
= encodedKey
;
521 unsigned remLen
= encodedKeyLen
;
522 CSSM_RETURN ourRtn
= CSSM_OK
;
524 /* length: ID string, NULL, Cipher, 4-byte spare */
525 if(remLen
< (len
+ 6)) {
526 errorLog0("decodeOpenSSHv1PrivKey: short record(1)\n");
527 return CSSMERR_CSP_INVALID_KEY
;
530 /* ID string plus a NULL */
531 if(memcmp(authfile_id_string
, cp
, len
)) {
532 errorLog0("decodeOpenSSHv1PrivKey: bad header\n");
533 return CSSMERR_CSP_INVALID_KEY
;
539 unsigned char cipherSpec
= *cp
;
541 case SSH_CIPHER_NONE
:
542 if(decryptKey
!= NULL
) {
543 errorLog0("decodeOpenSSHv1PrivKey: Attempt to decrypt plaintext key\n");
544 return CSSMERR_CSP_INVALID_KEY
;
547 case SSH_CIPHER_3DES
:
548 if(decryptKey
== NULL
) {
549 errorLog0("decodeOpenSSHv1PrivKey: Encrypted key with no decryptKey\n");
550 return CSSMERR_CSP_INVALID_KEY
;
554 /* I hope we don't see any other values here */
555 errorLog1("decodeOpenSSHv1PrivKey: unknown cipherSpec (%u)\n", cipherSpec
);
556 return CSSMERR_CSP_INVALID_KEY
;
559 /* skip cipher, spares */
564 * Clear text public key:
569 if(remLen
< sizeof(uint32_t)) {
570 errorLog0("decodeOpenSSHv1PrivKey: bad len(1)\n");
571 return CSSMERR_CSP_INVALID_KEY
;
574 readUint32(cp
, remLen
);
575 rsa
->n
= readBigNum(cp
, remLen
);
577 errorLog0("decodeOpenSSHv1PrivKey: error decoding n\n");
578 return CSSMERR_CSP_INVALID_KEY
;
580 rsa
->e
= readBigNum(cp
, remLen
);
582 errorLog0("decodeOpenSSHv1PrivKey: error decoding e\n");
583 return CSSMERR_CSP_INVALID_KEY
;
586 /* comment string: 4-byte length and the string w/o NULL */
587 if(remLen
< sizeof(uint32_t)) {
588 errorLog0("decodeOpenSSHv1PrivKey: bad len(2)\n");
589 return CSSMERR_CSP_INVALID_KEY
;
591 uint32_t commLen
= readUint32(cp
, remLen
);
592 if(commLen
> remLen
) {
593 errorLog0("decodeOpenSSHv1PrivKey: bad len(3)\n");
594 return CSSMERR_CSP_INVALID_KEY
;
597 *comment
= (uint8
*)malloc(commLen
);
598 *commentLen
= commLen
;
599 memcpy(*comment
, cp
, commLen
);
605 /* everything that remains is ciphertext */
606 unsigned char *ptext
= (unsigned char *)malloc(remLen
);
607 unsigned ptextLen
= 0;
608 ourRtn
= ssh1DES3Crypt(cipherSpec
, false, cp
, remLen
,
609 decryptKey
, decryptKey
? CC_MD5_DIGEST_LENGTH
: 0,
612 errorLog0("UnwrapKeyOpenSSH1: decrypt error\n");
613 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
617 /* plaintext contents:
619 [0-1] -- random bytes
620 [2-3] -- copy of [01] for passphrase validity checking
622 buffer_put_bignum(iqmp)
630 errorLog0("UnwrapKeyOpenSSH1: bad len(4)\n");
631 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
634 if((cp
[0] != cp
[2]) || (cp
[1] != cp
[3])) {
636 errorLog0("UnwrapKeyOpenSSH1: check byte error\n");
637 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
643 /* remainder comprises private portion of RSA key */
644 rsa
->d
= readBigNum(cp
, remLen
);
646 errorLog0("UnwrapKeyOpenSSH1: error decoding d\n");
647 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
650 rsa
->iqmp
= readBigNum(cp
, remLen
);
651 if(rsa
->iqmp
== NULL
) {
652 errorLog0("UnwrapKeyOpenSSH1: error decoding iqmp\n");
653 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
656 rsa
->q
= readBigNum(cp
, remLen
);
658 errorLog0("UnwrapKeyOpenSSH1: error decoding q\n");
659 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
662 rsa
->p
= readBigNum(cp
, remLen
);
664 errorLog0("UnwrapKeyOpenSSH1: error decoding p\n");
665 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
669 /* calculate d mod{p-1,q-1} */
670 ourRtn
= rsa_generate_additional_parameters(rsa
);
674 memset(ptext
, 0, ptextLen
);
680 void AppleCSPSession::UnwrapKeyOpenSSH1(
681 CSSM_CC_HANDLE CCHandle
,
682 const Context
&context
,
683 const CssmKey
&WrappedKey
,
684 const CSSM_RESOURCE_CONTROL_CONTEXT
*CredAndAclEntry
,
685 CssmKey
&UnwrappedKey
,
686 CssmData
&DescriptiveData
,
687 CSSM_PRIVILEGE Privilege
,
688 cspKeyStorage keyStorage
)
691 * Get the raw password bits from the unwrapping key.
692 * Our caller verified that the context has a symmetric key; this call
693 * ensures that the key is of algorithm CSSM_ALGID_OPENSSH1.
695 CSSM_SIZE unwrapKeyLen
= 0;
696 uint8
*unwrapKey
= NULL
;
698 AppleCSPContext::symmetricKeyBits(context
, *this,
699 CSSM_ALGID_OPENSSH1
, CSSM_KEYUSE_UNWRAP
,
700 unwrapKey
, unwrapKeyLen
);
701 if((unwrapKey
== NULL
) || (unwrapKeyLen
!= CC_MD5_DIGEST_LENGTH
)) {
702 errorLog0("AppleCSPSession::UnwrapKeyOpenSSH1: bad unwrapping key length\n");
703 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
706 RSA
*rsa
= RSA_new();
707 CSSM_RETURN ourRtn
= CSSM_OK
;
708 unsigned char *comment
= NULL
;
709 unsigned commentLen
= 0;
710 RSABinaryKey
*binKey
= NULL
;
712 ourRtn
= decodeOpenSSHv1PrivKey((const unsigned char *)WrappedKey
.KeyData
.Data
,
713 (unsigned)WrappedKey
.KeyData
.Length
,
714 rsa
, unwrapKey
, &comment
, &commentLen
);
719 setUpCssmData(DescriptiveData
, commentLen
, normAllocator
);
720 memcpy(DescriptiveData
.Data
, comment
, commentLen
);
725 * Our caller ensured that we're only generating a reference key,
726 * which we do like so:
728 binKey
= new RSABinaryKey(rsa
);
729 addRefKey(*binKey
, UnwrappedKey
);
736 CssmError::throwMe(ourRtn
);