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.h>
39 #include <openssl/bn.h>
40 #include <security_utilities/devrandom.h>
42 static const char *authfile_id_string
= "SSH PRIVATE KEY FILE FORMAT 1.1\n";
44 /* default comment on encode if app doesn't provide DescriptiveData */
45 #define OPENSSH1_COMMENT "Encoded by Mac OS X Security.framework"
47 /* from openssh cipher.h */
48 #define SSH_CIPHER_NONE 0 /* no encryption */
49 #define SSH_CIPHER_IDEA 1 /* IDEA CFB */
50 #define SSH_CIPHER_DES 2 /* DES CBC */
51 #define SSH_CIPHER_3DES 3 /* 3DES CBC */
52 #define SSH_CIPHER_BROKEN_TSS 4 /* TRI's Simple Stream encryption CBC */
53 #define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */
54 #define SSH_CIPHER_BLOWFISH 6
55 #define SSH_CIPHER_RESERVED 7
57 #pragma mark --- utilities ---
59 static void appendUint16(
60 CFMutableDataRef cfOut
,
63 UInt8 buf
[sizeof(uint16_t)];
68 CFDataAppendBytes(cfOut
, buf
, sizeof(uint16_t));
71 static uint16_t readUint16(
72 const unsigned char *&cp
, // IN/OUT
73 unsigned &len
) // IN/OUT
82 /* Write BIGNUM, OpenSSH-1 version */
83 static CSSM_RETURN
appendBigNum(
84 CFMutableDataRef cfOut
,
87 /* 16 bits of numbits */
88 unsigned numBits
= BN_num_bits(bn
);
89 appendUint16(cfOut
, numBits
);
91 /* serialize the bytes */
92 int numBytes
= (numBits
+ 7) / 8;
93 unsigned char outBytes
[numBytes
]; // gcc is so cool...
94 int moved
= BN_bn2bin(bn
, outBytes
);
95 if(moved
!= numBytes
) {
96 errorLog0("appendBigNum: BN_bn2bin() screwup\n");
97 return CSSMERR_CSP_INTERNAL_ERROR
;
99 CFDataAppendBytes(cfOut
, (UInt8
*)outBytes
, numBytes
);
103 /* Read BIGNUM, OpenSSH-1 version */
104 static BIGNUM
*readBigNum(
105 const unsigned char *&cp
, // IN/OUT
106 unsigned &remLen
) // IN/OUT
108 if(remLen
< sizeof(uint16_t)) {
109 errorLog0("readBigNum: short record(1)\n");
112 uint16_t numBits
= readUint16(cp
, remLen
);
113 unsigned bytes
= (numBits
+ 7) / 8;
115 errorLog0("readBigNum: short record(2)\n");
118 BIGNUM
*bn
= BN_bin2bn(cp
, bytes
, NULL
);
120 errorLog0("readBigNum: BN_bin2bn error\n");
129 * Calculate d mod{p-1,q-1}
130 * Used when decoding OpenSSH-1 private RSA key.
132 static CSSM_RETURN
rsa_generate_additional_parameters(RSA
*rsa
)
137 if((rsa
->dmq1
= BN_new()) == NULL
) {
138 errorLog0("rsa_generate_additional_parameters: BN_new failed");
139 return CSSMERR_CSP_INTERNAL_ERROR
;
141 if((rsa
->dmp1
= BN_new()) == NULL
) {
142 errorLog0("rsa_generate_additional_parameters: BN_new failed");
143 return CSSMERR_CSP_INTERNAL_ERROR
;
145 if ((aux
= BN_new()) == NULL
) {
146 errorLog0("rsa_generate_additional_parameters: BN_new failed");
147 return CSSMERR_CSP_INTERNAL_ERROR
;
149 if ((ctx
= BN_CTX_new()) == NULL
) {
150 errorLog0("rsa_generate_additional_parameters: BN_CTX_new failed");
152 return CSSMERR_CSP_INTERNAL_ERROR
;
155 BN_sub(aux
, rsa
->q
, BN_value_one());
156 BN_mod(rsa
->dmq1
, rsa
->d
, aux
, ctx
);
158 BN_sub(aux
, rsa
->p
, BN_value_one());
159 BN_mod(rsa
->dmp1
, rsa
->d
, aux
, ctx
);
166 #pragma mark --- encrypt/decrypt ---
169 * Encrypt/decrypt the secret portion of an OpenSSHv1 format RSA private key.
171 static CSSM_RETURN
ssh1DES3Crypt(
172 unsigned char cipher
,
174 const unsigned char *inText
,
176 const uint8
*key
, // MD5(password)
178 unsigned char *outText
, // data RETURNED here, caller mallocs.
179 unsigned *outTextLen
) // RETURNED
182 case SSH_CIPHER_3DES
:
184 case SSH_CIPHER_NONE
:
185 /* cleartext RSA private key, e.g. host key. */
186 memmove(outText
, inText
, inTextLen
);
187 *outTextLen
= inTextLen
;
190 /* who knows how we're going to figure these out */
191 errorLog1("***ssh1DES3Crypt: Unsupported cipher (%u)\n", cipher
);
192 return CSSMERR_CSP_INVALID_KEY
;
195 if(keyLen
!= CC_MD5_DIGEST_LENGTH
) {
196 errorLog0("ssh1DES3Crypt: bad key length\n");
197 return CSSMERR_CSP_INVALID_KEY
;
200 /* three keys from that, like so: */
201 unsigned char k1
[kCCKeySizeDES
];
202 unsigned char k2
[kCCKeySizeDES
];
203 unsigned char k3
[kCCKeySizeDES
];
204 memmove(k1
, key
, kCCKeySizeDES
);
205 memmove(k2
, key
+ kCCKeySizeDES
, kCCKeySizeDES
);
206 memmove(k3
, key
, kCCKeySizeDES
);
219 /* the openssh v1 pseudo triple DES. Each DES pass has its own CBC. */
222 CCCryptorStatus cstat
= CCCrypt(op1_3
, kCCAlgorithmDES
,
227 outText
, inTextLen
, &moved
);
229 /* should never happen */
230 errorLog1("***ssh1DES3Crypt: CCCrypt()(1) returned %u\n", (unsigned)cstat
);
231 return CSSMERR_CSP_INTERNAL_ERROR
;
233 cstat
= CCCrypt(op2
, kCCAlgorithmDES
,
234 0, // no padding - SSH does that itself
238 outText
, inTextLen
, &moved
);
240 errorLog1("***ssh1DES3Crypt: CCCrypt()(2) returned %u\n", (unsigned)cstat
);
241 return CSSMERR_CSP_INTERNAL_ERROR
;
243 cstat
= CCCrypt(op1_3
, kCCAlgorithmDES
,
244 0, // no padding - SSH does that itself
248 outText
, inTextLen
, &moved
);
250 errorLog1("***ssh1DES3Crypt: CCCrypt()(3) returned %u\n", (unsigned)cstat
);
251 return CSSMERR_CSP_INTERNAL_ERROR
;
254 *outTextLen
= (unsigned)moved
;
258 #pragma mark --- DeriveKey ---
261 * Key derivation for OpenSSH1 private key wrap/unwrap.
262 * This is pretty trivial, it's just an MD5() operation. The main
263 * purpose for doing this in a DeriveKey operation is to enable the
264 * use of either Secure Passphrases, obtained by securityd/SecurityAgent,
265 * or app-specified data.
267 void AppleCSPSession::DeriveKey_OpenSSH1(
268 const Context
&context
,
269 CSSM_ALGORITHMS algId
,
270 const CssmData
&Param
, // IV optional, mallocd by app to indicate
272 CSSM_DATA
*keyData
) // mallocd by caller to indicate size - must be
273 // size of MD5 digest!
275 CSSM_DATA pwd
= {0, NULL
};
277 if(keyData
->Length
!= CC_MD5_DIGEST_LENGTH
) {
278 errorLog0("DeriveKey_OpenSSH1: invalid key length\n");
279 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_SIZE
);
282 /* password from either Seed.Param or from base key */
283 CssmCryptoData
*cryptData
=
284 context
.get
<CssmCryptoData
>(CSSM_ATTRIBUTE_SEED
);
285 if((cryptData
!= NULL
) && (cryptData
->Param
.Length
!= 0)) {
286 pwd
= cryptData
->Param
;
289 /* Get secure passphrase from base key */
290 CssmKey
*passKey
= context
.get
<CssmKey
>(CSSM_ATTRIBUTE_KEY
);
291 if (passKey
!= NULL
) {
292 AppleCSPContext::symmetricKeyBits(context
, *this,
293 CSSM_ALGID_SECURE_PASSPHRASE
, CSSM_KEYUSE_DERIVE
,
294 pwd
.Data
, pwd
.Length
);
298 if(pwd
.Data
== NULL
) {
299 errorLog0("DeriveKey_PKCS5_V1_5: null Passphrase\n");
300 CssmError::throwMe(CSSMERR_CSP_INVALID_DATA
);
302 if(pwd
.Length
== 0) {
303 errorLog0("DeriveKey_PKCS5_V1_5: zero length passphrase\n");
304 CssmError::throwMe(CSSMERR_CSP_INVALID_INPUT_POINTER
);
308 CC_MD5(pwd
.Data
, (CC_LONG
)pwd
.Length
, keyData
->Data
);
312 #pragma mark --- Encode/Wrap OpenSSHv1 private key ---
315 * Encode OpenSSHv1 private key, with or without encryption.
316 * This used for generating key blobs of format CSSM_KEYBLOB_RAW_FORMAT_OPENSSH
317 * as well as wrapping keys in format CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1.
319 CSSM_RETURN
encodeOpenSSHv1PrivKey(
321 const uint8
*comment
, /* optional */
323 const uint8
*encryptKey
, /* optional; if present, it's 16 bytes of MD5(password) */
324 CFDataRef
*encodedKey
) /* RETURNED */
326 CFMutableDataRef cfOut
= CFDataCreateMutable(NULL
, 0);
327 CSSM_RETURN ourRtn
= CSSM_OK
;
329 /* ID string including NULL */
330 CFDataAppendBytes(cfOut
, (const UInt8
*)authfile_id_string
, strlen(authfile_id_string
) + 1);
332 /* one byte cipher */
333 UInt8 cipherSpec
= encryptKey
? SSH_CIPHER_3DES
: SSH_CIPHER_NONE
;
334 CFDataAppendBytes(cfOut
, &cipherSpec
, 1);
337 UInt8 spares
[4] = {0};
338 CFDataAppendBytes(cfOut
, spares
, 4);
341 * Clear text public key:
346 uint32_t keybits
= RSA_size(rsa
) * 8;
347 appendUint32(cfOut
, keybits
);
348 appendBigNum(cfOut
, rsa
->n
);
349 appendBigNum(cfOut
, rsa
->e
);
353 * The format appears to require this, or else we wouldn't know
354 * when we've got to the ciphertext on decode.
356 if((comment
== NULL
) || (commentLen
== 0)) {
357 comment
= (const UInt8
*)OPENSSH1_COMMENT
;
358 commentLen
= strlen(OPENSSH1_COMMENT
);
360 appendUint32(cfOut
, commentLen
);
361 CFDataAppendBytes(cfOut
, comment
, commentLen
);
364 * Remainder is encrypted, consisting of
366 * [0-1] -- random bytes
367 * [2-3] -- copy of [01] for passphrase validity checking
368 * buffer_put_bignum(d)
369 * buffer_put_bignum(iqmp)
370 * buffer_put_bignum(q)
371 * buffer_put_bignum(p)
374 CFMutableDataRef ptext
= CFDataCreateMutable(NULL
, 0);
376 /* [0..3] check bytes */
378 DevRandomGenerator rng
= DevRandomGenerator();
379 rng
.random(checkBytes
, 2);
380 checkBytes
[2] = checkBytes
[0];
381 checkBytes
[3] = checkBytes
[1];
382 CFDataAppendBytes(ptext
, checkBytes
, 4);
385 appendBigNum(ptext
, rsa
->d
);
386 appendBigNum(ptext
, rsa
->iqmp
);
387 appendBigNum(ptext
, rsa
->q
);
388 appendBigNum(ptext
, rsa
->p
);
390 /* pad to block boundary */
391 CFIndex ptextLen
= CFDataGetLength(ptext
);
392 unsigned padding
= 0;
393 unsigned rem
= (unsigned)ptextLen
& 0x7;
398 for(unsigned dex
=0; dex
<padding
; dex
++) {
399 CFDataAppendBytes(ptext
, &padByte
, 1);
403 ptextLen
= CFDataGetLength(ptext
);
404 unsigned char ctext
[ptextLen
];
406 ourRtn
= ssh1DES3Crypt(cipherSpec
, true,
407 (unsigned char *)CFDataGetBytePtr(ptext
), (unsigned)ptextLen
,
408 encryptKey
, encryptKey
? CC_MD5_DIGEST_LENGTH
: 0,
414 /* appended encrypted portion */
415 CFDataAppendBytes(cfOut
, ctext
, ctextLen
);
418 /* it would be proper to zero out ptext here, but we can't do that to a CFData */
423 void AppleCSPSession::WrapKeyOpenSSH1(
424 CSSM_CC_HANDLE CCHandle
,
425 const Context
&context
,
426 const AccessCredentials
&AccessCred
,
427 BinaryKey
&unwrappedBinKey
,
429 bool allocdRawBlob
, // callee has to free rawBlob
430 const CssmData
*DescriptiveData
,
432 CSSM_PRIVILEGE Privilege
)
435 * The job here is to convert the RSA key in binKey to the OpenSSHv1 private
436 * key format, and drop that into WrappedKey.KeyData (allocated by the session).
438 * This cast throws an exception if the key is not an RSA key, which
439 * would be a major bogon, since our caller verified that the unwrapped key
440 * is a private RSA key.
442 RSABinaryKey
&rPubBinKey
= dynamic_cast<RSABinaryKey
&>(unwrappedBinKey
);
443 RSA
*rsa
= rPubBinKey
.mRsaKey
;
444 CASSERT(rsa
!= NULL
);
447 * Get the raw password bits from the wrapping key.
448 * Our caller verified that the context has a symmetric key; this call
449 * ensures that the key is of algorithm CSSM_ALGID_OPENSSH1.
450 * Key length 0 means no encryption.
452 CSSM_SIZE wrappingKeyLen
= 0;
453 uint8
*wrappingKey
= NULL
;
455 AppleCSPContext::symmetricKeyBits(context
, *this,
456 CSSM_ALGID_OPENSSH1
, CSSM_KEYUSE_WRAP
,
457 wrappingKey
, wrappingKeyLen
);
458 if(wrappingKeyLen
!= CC_MD5_DIGEST_LENGTH
) {
459 errorLog0("AppleCSPSession::WrapKeyOpenSSH1: bad wrapping key length\n");
460 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
463 CFDataRef cfOut
= NULL
;
466 * Optional comment string from DescriptiveData.
468 const UInt8
*comment
= NULL
;
469 unsigned commentLen
= 0;
470 if((DescriptiveData
!= NULL
) && (DescriptiveData
->Length
!= 0)) {
471 comment
= (const UInt8
*)DescriptiveData
->Data
;
472 commentLen
= (unsigned)DescriptiveData
->Length
;
475 /* generate the encrypted blob */
476 CSSM_RETURN crtn
= encodeOpenSSHv1PrivKey(rsa
, comment
, commentLen
, wrappingKey
, &cfOut
);
478 CssmError::throwMe(crtn
);
481 /* allocate key data in session's memory space */
482 CFIndex len
= CFDataGetLength(cfOut
);
483 setUpData(WrappedKey
.KeyData
, len
, normAllocator
);
484 memmove(WrappedKey
.KeyData
.Data
, CFDataGetBytePtr(cfOut
), len
);
487 /* outgoing header */
488 WrappedKey
.KeyHeader
.BlobType
= CSSM_KEYBLOB_WRAPPED
;
489 // OK to be zero or not present
490 WrappedKey
.KeyHeader
.WrapMode
= CSSM_ALGMODE_NONE
;
491 WrappedKey
.KeyHeader
.Format
= CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1
;
494 #pragma mark --- Decode/Unwrap OpenSSHv1 private key ---
497 * Decode OpenSSHv1 private, optionally decrypting the secret portion.
498 * This used for decoding key blobs of format CSSM_KEYBLOB_RAW_FORMAT_OPENSSH
499 * as well as unwrapping keys in format CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1.
501 CSSM_RETURN
decodeOpenSSHv1PrivKey(
502 const unsigned char *encodedKey
,
503 unsigned encodedKeyLen
,
505 const uint8
*decryptKey
, /* optional; if present, it's 16 bytes of MD5(password) */
506 uint8
**comment
, /* optional, mallocd and RETURNED */
507 unsigned *commentLen
) /* RETURNED */
509 unsigned len
= (unsigned)strlen(authfile_id_string
);
510 const unsigned char *cp
= encodedKey
;
511 unsigned remLen
= encodedKeyLen
;
512 CSSM_RETURN ourRtn
= CSSM_OK
;
514 /* length: ID string, NULL, Cipher, 4-byte spare */
515 if(remLen
< (len
+ 6)) {
516 errorLog0("decodeOpenSSHv1PrivKey: short record(1)\n");
517 return CSSMERR_CSP_INVALID_KEY
;
520 /* ID string plus a NULL */
521 if(memcmp(authfile_id_string
, cp
, len
)) {
522 errorLog0("decodeOpenSSHv1PrivKey: bad header\n");
523 return CSSMERR_CSP_INVALID_KEY
;
529 unsigned char cipherSpec
= *cp
;
531 case SSH_CIPHER_NONE
:
532 if(decryptKey
!= NULL
) {
533 errorLog0("decodeOpenSSHv1PrivKey: Attempt to decrypt plaintext key\n");
534 return CSSMERR_CSP_INVALID_KEY
;
537 case SSH_CIPHER_3DES
:
538 if(decryptKey
== NULL
) {
539 errorLog0("decodeOpenSSHv1PrivKey: Encrypted key with no decryptKey\n");
540 return CSSMERR_CSP_INVALID_KEY
;
544 /* I hope we don't see any other values here */
545 errorLog1("decodeOpenSSHv1PrivKey: unknown cipherSpec (%u)\n", cipherSpec
);
546 return CSSMERR_CSP_INVALID_KEY
;
549 /* skip cipher, spares */
554 * Clear text public key:
559 if(remLen
< sizeof(uint32_t)) {
560 errorLog0("decodeOpenSSHv1PrivKey: bad len(1)\n");
561 return CSSMERR_CSP_INVALID_KEY
;
564 readUint32(cp
, remLen
);
565 rsa
->n
= readBigNum(cp
, remLen
);
567 errorLog0("decodeOpenSSHv1PrivKey: error decoding n\n");
568 return CSSMERR_CSP_INVALID_KEY
;
570 rsa
->e
= readBigNum(cp
, remLen
);
572 errorLog0("decodeOpenSSHv1PrivKey: error decoding e\n");
573 return CSSMERR_CSP_INVALID_KEY
;
576 /* comment string: 4-byte length and the string w/o NULL */
577 if(remLen
< sizeof(uint32_t)) {
578 errorLog0("decodeOpenSSHv1PrivKey: bad len(2)\n");
579 return CSSMERR_CSP_INVALID_KEY
;
581 uint32_t commLen
= readUint32(cp
, remLen
);
582 if(commLen
> remLen
) {
583 errorLog0("decodeOpenSSHv1PrivKey: bad len(3)\n");
584 return CSSMERR_CSP_INVALID_KEY
;
587 *comment
= (uint8
*)malloc(commLen
);
588 *commentLen
= commLen
;
589 memcpy(*comment
, cp
, commLen
);
595 /* everything that remains is ciphertext */
596 unsigned char *ptext
= (unsigned char *)malloc(remLen
);
597 unsigned ptextLen
= 0;
598 ourRtn
= ssh1DES3Crypt(cipherSpec
, false, cp
, remLen
,
599 decryptKey
, decryptKey
? CC_MD5_DIGEST_LENGTH
: 0,
602 errorLog0("UnwrapKeyOpenSSH1: decrypt error\n");
603 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
607 /* plaintext contents:
609 [0-1] -- random bytes
610 [2-3] -- copy of [01] for passphrase validity checking
612 buffer_put_bignum(iqmp)
620 errorLog0("UnwrapKeyOpenSSH1: bad len(4)\n");
621 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
624 if((cp
[0] != cp
[2]) || (cp
[1] != cp
[3])) {
626 errorLog0("UnwrapKeyOpenSSH1: check byte error\n");
627 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
633 /* remainder comprises private portion of RSA key */
634 rsa
->d
= readBigNum(cp
, remLen
);
636 errorLog0("UnwrapKeyOpenSSH1: error decoding d\n");
637 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
640 rsa
->iqmp
= readBigNum(cp
, remLen
);
641 if(rsa
->iqmp
== NULL
) {
642 errorLog0("UnwrapKeyOpenSSH1: error decoding iqmp\n");
643 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
646 rsa
->q
= readBigNum(cp
, remLen
);
648 errorLog0("UnwrapKeyOpenSSH1: error decoding q\n");
649 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
652 rsa
->p
= readBigNum(cp
, remLen
);
654 errorLog0("UnwrapKeyOpenSSH1: error decoding p\n");
655 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
659 /* calculate d mod{p-1,q-1} */
660 ourRtn
= rsa_generate_additional_parameters(rsa
);
664 memset(ptext
, 0, ptextLen
);
670 void AppleCSPSession::UnwrapKeyOpenSSH1(
671 CSSM_CC_HANDLE CCHandle
,
672 const Context
&context
,
673 const CssmKey
&WrappedKey
,
674 const CSSM_RESOURCE_CONTROL_CONTEXT
*CredAndAclEntry
,
675 CssmKey
&UnwrappedKey
,
676 CssmData
&DescriptiveData
,
677 CSSM_PRIVILEGE Privilege
,
678 cspKeyStorage keyStorage
)
681 * Get the raw password bits from the unwrapping key.
682 * Our caller verified that the context has a symmetric key; this call
683 * ensures that the key is of algorithm CSSM_ALGID_OPENSSH1.
685 CSSM_SIZE unwrapKeyLen
= 0;
686 uint8
*unwrapKey
= NULL
;
688 AppleCSPContext::symmetricKeyBits(context
, *this,
689 CSSM_ALGID_OPENSSH1
, CSSM_KEYUSE_UNWRAP
,
690 unwrapKey
, unwrapKeyLen
);
691 if((unwrapKey
== NULL
) || (unwrapKeyLen
!= CC_MD5_DIGEST_LENGTH
)) {
692 errorLog0("AppleCSPSession::UnwrapKeyOpenSSH1: bad unwrapping key length\n");
693 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
696 RSA
*rsa
= RSA_new();
697 CSSM_RETURN ourRtn
= CSSM_OK
;
698 unsigned char *comment
= NULL
;
699 unsigned commentLen
= 0;
700 RSABinaryKey
*binKey
= NULL
;
702 ourRtn
= decodeOpenSSHv1PrivKey((const unsigned char *)WrappedKey
.KeyData
.Data
,
703 (unsigned)WrappedKey
.KeyData
.Length
,
704 rsa
, unwrapKey
, &comment
, &commentLen
);
709 setUpCssmData(DescriptiveData
, commentLen
, normAllocator
);
710 memcpy(DescriptiveData
.Data
, comment
, commentLen
);
714 * Our caller ensured that we're only generating a reference key,
715 * which we do like so:
717 binKey
= new RSABinaryKey(rsa
);
718 addRefKey(*binKey
, UnwrappedKey
);
725 CssmError::throwMe(ourRtn
);