2 * Copyright (c) 2006 Apple Computer, 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.
27 * Created 8/29/2006 by dmitch.
30 #include "AppleCSPSession.h"
31 #include "AppleCSPContext.h"
32 #include "AppleCSPUtils.h"
33 #include "AppleCSPKeys.h"
34 #include "RSA_DSA_Keys.h"
35 #include "opensshCoding.h"
36 #include "cspdebugging.h"
37 #include <CommonCrypto/CommonDigest.h>
38 #include <CommonCrypto/CommonCryptor.h>
39 #include <openssl/rsa.h>
40 #include <openssl/bn.h>
41 #include <security_utilities/devrandom.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
;
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
, 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 unsigned ptextLen
= CFDataGetLength(ptext
);
393 unsigned padding
= 0;
394 unsigned rem
= ptextLen
& 0x7;
399 for(unsigned dex
=0; dex
<padding
; dex
++) {
400 CFDataAppendBytes(ptext
, &padByte
, 1);
404 ptextLen
= CFDataGetLength(ptext
);
405 unsigned char ctext
[ptextLen
];
407 ourRtn
= ssh1DES3Crypt(cipherSpec
, true,
408 (unsigned char *)CFDataGetBytePtr(ptext
), ptextLen
,
409 encryptKey
, encryptKey
? CC_MD5_DIGEST_LENGTH
: 0,
415 /* appended encrypted portion */
416 CFDataAppendBytes(cfOut
, ctext
, ctextLen
);
419 /* it would be proper to zero out ptext here, but we can't do that to a CFData */
424 void AppleCSPSession::WrapKeyOpenSSH1(
425 CSSM_CC_HANDLE CCHandle
,
426 const Context
&context
,
427 const AccessCredentials
&AccessCred
,
428 BinaryKey
&unwrappedBinKey
,
430 bool allocdRawBlob
, // callee has to free rawBlob
431 const CssmData
*DescriptiveData
,
433 CSSM_PRIVILEGE Privilege
)
436 * The job here is to convert the RSA key in binKey to the OpenSSHv1 private
437 * key format, and drop that into WrappedKey.KeyData (allocated by the session).
439 * This cast throws an exception if the key is not an RSA key, which
440 * would be a major bogon, since our caller verified that the unwrapped key
441 * is a private RSA key.
443 RSABinaryKey
&rPubBinKey
= dynamic_cast<RSABinaryKey
&>(unwrappedBinKey
);
444 RSA
*rsa
= rPubBinKey
.mRsaKey
;
445 CASSERT(rsa
!= NULL
);
448 * Get the raw password bits from the wrapping key.
449 * Our caller verified that the context has a symmetric key; this call
450 * ensures that the key is of algorithm CSSM_ALGID_OPENSSH1.
451 * Key length 0 means no encryption.
453 CSSM_SIZE wrappingKeyLen
= 0;
454 uint8
*wrappingKey
= NULL
;
456 AppleCSPContext::symmetricKeyBits(context
, *this,
457 CSSM_ALGID_OPENSSH1
, CSSM_KEYUSE_WRAP
,
458 wrappingKey
, wrappingKeyLen
);
459 if(wrappingKeyLen
!= CC_MD5_DIGEST_LENGTH
) {
460 errorLog0("AppleCSPSession::WrapKeyOpenSSH1: bad wrapping key length\n");
461 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
464 CFDataRef cfOut
= NULL
;
467 * Optional comment string from DescriptiveData.
469 const UInt8
*comment
= NULL
;
470 unsigned commentLen
= 0;
471 if((DescriptiveData
!= NULL
) && (DescriptiveData
->Length
!= 0)) {
472 comment
= (const UInt8
*)DescriptiveData
->Data
;
473 commentLen
= DescriptiveData
->Length
;
476 /* generate the encrypted blob */
477 CSSM_RETURN crtn
= encodeOpenSSHv1PrivKey(rsa
, comment
, commentLen
, wrappingKey
, &cfOut
);
479 CssmError::throwMe(crtn
);
482 /* allocate key data in session's memory space */
483 unsigned len
= CFDataGetLength(cfOut
);
484 setUpData(WrappedKey
.KeyData
, len
, normAllocator
);
485 memmove(WrappedKey
.KeyData
.Data
, CFDataGetBytePtr(cfOut
), len
);
488 /* outgoing header */
489 WrappedKey
.KeyHeader
.BlobType
= CSSM_KEYBLOB_WRAPPED
;
490 // OK to be zero or not present
491 WrappedKey
.KeyHeader
.WrapMode
= CSSM_ALGMODE_NONE
;
492 WrappedKey
.KeyHeader
.Format
= CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1
;
495 #pragma mark --- Decode/Unwrap OpenSSHv1 private key ---
498 * Decode OpenSSHv1 private, optionally decrypting the secret portion.
499 * This used for decoding key blobs of format CSSM_KEYBLOB_RAW_FORMAT_OPENSSH
500 * as well as unwrapping keys in format CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1.
502 CSSM_RETURN
decodeOpenSSHv1PrivKey(
503 const unsigned char *encodedKey
,
504 unsigned encodedKeyLen
,
506 const uint8
*decryptKey
, /* optional; if present, it's 16 bytes of MD5(password) */
507 uint8
**comment
, /* optional, mallocd and RETURNED */
508 unsigned *commentLen
) /* RETURNED */
510 unsigned len
= strlen(authfile_id_string
);
511 const unsigned char *cp
= encodedKey
;
512 unsigned remLen
= encodedKeyLen
;
513 CSSM_RETURN ourRtn
= CSSM_OK
;
515 /* length: ID string, NULL, Cipher, 4-byte spare */
516 if(remLen
< (len
+ 6)) {
517 errorLog0("decodeOpenSSHv1PrivKey: short record(1)\n");
518 return CSSMERR_CSP_INVALID_KEY
;
521 /* ID string plus a NULL */
522 if(memcmp(authfile_id_string
, cp
, len
)) {
523 errorLog0("decodeOpenSSHv1PrivKey: bad header\n");
524 return CSSMERR_CSP_INVALID_KEY
;
530 unsigned char cipherSpec
= *cp
;
532 case SSH_CIPHER_NONE
:
533 if(decryptKey
!= NULL
) {
534 errorLog0("decodeOpenSSHv1PrivKey: Attempt to decrypt plaintext key\n");
535 return CSSMERR_CSP_INVALID_KEY
;
538 case SSH_CIPHER_3DES
:
539 if(decryptKey
== NULL
) {
540 errorLog0("decodeOpenSSHv1PrivKey: Encrypted key with no decryptKey\n");
541 return CSSMERR_CSP_INVALID_KEY
;
545 /* I hope we don't see any other values here */
546 errorLog1("decodeOpenSSHv1PrivKey: unknown cipherSpec (%u)\n", cipherSpec
);
547 return CSSMERR_CSP_INVALID_KEY
;
550 /* skip cipher, spares */
555 * Clear text public key:
560 if(remLen
< sizeof(uint32_t)) {
561 errorLog0("decodeOpenSSHv1PrivKey: bad len(1)\n");
562 return CSSMERR_CSP_INVALID_KEY
;
565 readUint32(cp
, remLen
);
566 rsa
->n
= readBigNum(cp
, remLen
);
568 errorLog0("decodeOpenSSHv1PrivKey: error decoding n\n");
569 return CSSMERR_CSP_INVALID_KEY
;
571 rsa
->e
= readBigNum(cp
, remLen
);
573 errorLog0("decodeOpenSSHv1PrivKey: error decoding e\n");
574 return CSSMERR_CSP_INVALID_KEY
;
577 /* comment string: 4-byte length and the string w/o NULL */
578 if(remLen
< sizeof(uint32_t)) {
579 errorLog0("decodeOpenSSHv1PrivKey: bad len(2)\n");
580 return CSSMERR_CSP_INVALID_KEY
;
582 uint32_t commLen
= readUint32(cp
, remLen
);
583 if(commLen
> remLen
) {
584 errorLog0("decodeOpenSSHv1PrivKey: bad len(3)\n");
585 return CSSMERR_CSP_INVALID_KEY
;
588 *comment
= (uint8
*)malloc(commLen
);
589 *commentLen
= commLen
;
590 memcpy(*comment
, cp
, commLen
);
596 /* everything that remains is ciphertext */
597 unsigned char *ptext
= (unsigned char *)malloc(remLen
);
598 unsigned ptextLen
= 0;
599 ourRtn
= ssh1DES3Crypt(cipherSpec
, false, cp
, remLen
,
600 decryptKey
, decryptKey
? CC_MD5_DIGEST_LENGTH
: 0,
603 errorLog0("UnwrapKeyOpenSSH1: decrypt error\n");
604 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
608 /* plaintext contents:
610 [0-1] -- random bytes
611 [2-3] -- copy of [01] for passphrase validity checking
613 buffer_put_bignum(iqmp)
621 errorLog0("UnwrapKeyOpenSSH1: bad len(4)\n");
622 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
625 if((cp
[0] != cp
[2]) || (cp
[1] != cp
[3])) {
627 errorLog0("UnwrapKeyOpenSSH1: check byte error\n");
628 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
634 /* remainder comprises private portion of RSA key */
635 rsa
->d
= readBigNum(cp
, remLen
);
637 errorLog0("UnwrapKeyOpenSSH1: error decoding d\n");
638 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
641 rsa
->iqmp
= readBigNum(cp
, remLen
);
642 if(rsa
->iqmp
== NULL
) {
643 errorLog0("UnwrapKeyOpenSSH1: error decoding iqmp\n");
644 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
647 rsa
->q
= readBigNum(cp
, remLen
);
649 errorLog0("UnwrapKeyOpenSSH1: error decoding q\n");
650 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
653 rsa
->p
= readBigNum(cp
, remLen
);
655 errorLog0("UnwrapKeyOpenSSH1: error decoding p\n");
656 ourRtn
= CSSMERR_CSP_INVALID_KEY
;
660 /* calculate d mod{p-1,q-1} */
661 ourRtn
= rsa_generate_additional_parameters(rsa
);
665 memset(ptext
, 0, ptextLen
);
671 void AppleCSPSession::UnwrapKeyOpenSSH1(
672 CSSM_CC_HANDLE CCHandle
,
673 const Context
&context
,
674 const CssmKey
&WrappedKey
,
675 const CSSM_RESOURCE_CONTROL_CONTEXT
*CredAndAclEntry
,
676 CssmKey
&UnwrappedKey
,
677 CssmData
&DescriptiveData
,
678 CSSM_PRIVILEGE Privilege
,
679 cspKeyStorage keyStorage
)
682 * Get the raw password bits from the unwrapping key.
683 * Our caller verified that the context has a symmetric key; this call
684 * ensures that the key is of algorithm CSSM_ALGID_OPENSSH1.
686 CSSM_SIZE unwrapKeyLen
= 0;
687 uint8
*unwrapKey
= NULL
;
689 AppleCSPContext::symmetricKeyBits(context
, *this,
690 CSSM_ALGID_OPENSSH1
, CSSM_KEYUSE_UNWRAP
,
691 unwrapKey
, unwrapKeyLen
);
692 if((unwrapKey
== NULL
) || (unwrapKeyLen
!= CC_MD5_DIGEST_LENGTH
)) {
693 errorLog0("AppleCSPSession::UnwrapKeyOpenSSH1: bad unwrapping key length\n");
694 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
697 RSA
*rsa
= RSA_new();
698 CSSM_RETURN ourRtn
= CSSM_OK
;
699 unsigned char *comment
= NULL
;
700 unsigned commentLen
= 0;
701 RSABinaryKey
*binKey
= NULL
;
703 ourRtn
= decodeOpenSSHv1PrivKey((const unsigned char *)WrappedKey
.KeyData
.Data
,
704 WrappedKey
.KeyData
.Length
,
705 rsa
, unwrapKey
, &comment
, &commentLen
);
710 setUpCssmData(DescriptiveData
, commentLen
, normAllocator
);
711 memcpy(DescriptiveData
.Data
, comment
, commentLen
);
715 * Our caller ensured that we're only generating a reference key,
716 * which we do like so:
718 binKey
= new RSABinaryKey(rsa
);
719 addRefKey(*binKey
, UnwrappedKey
);
726 CssmError::throwMe(ourRtn
);