2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 * openRsaSnacc.cpp - glue between openrsa and SNACC
22 #include "openRsaSnacc.h"
23 #include "opensslUtils.h"
24 #include <openssl/err.h>
25 #include <openssl/bn.h>
26 #include <openssl/crypto.h>
28 // bring in a ton of snacc-related stuff
29 #include <Security/asn-incl.h>
30 #include <Security/sm_vdatypes.h>
32 // snacc-generated - snacc really should place these in pkcs[78].h
33 #include <Security/sm_x501ud.h>
34 #include <Security/sm_x411ub.h>
35 #include <Security/sm_x411mtsas.h>
36 #include <Security/sm_x501if.h>
37 #include <Security/sm_x520sa.h>
38 #include <Security/sm_x509cmn.h>
39 #include <Security/sm_x509af.h>
40 #include <Security/sm_x509ce.h>
41 #include <Security/pkcs1oids.h>
42 #include <Security/pkcs9oids.h>
43 #include <Security/sm_cms.h>
44 #include <Security/sm_ess.h>
45 #include <Security/pkcs7.h>
46 #include <Security/pkcs8.h>
48 #include <Security/cdsaUtils.h>
49 #include <Security/debugging.h>
50 #include <Security/appleoids.h>
53 #define sslSnaccDebug(args...) debug("sslSnacc", ##args)
56 * Convert between SNACC-style BigIntegerStr and openssl-style BIGNUM.
58 BIGNUM
*bigIntStrToBn(
59 BigIntegerStr
&snaccInt
)
61 BIGNUM
*bn
= BN_new();
63 char *rawOcts
= snaccInt
;
64 unsigned numBytes
= snaccInt
.Len();
66 rtn
= BN_bin2bn((unsigned char *)rawOcts
, numBytes
, bn
);
69 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR
);
76 BigIntegerStr
&snaccInt
)
78 unsigned numBytes
= BN_num_bytes(bn
);
83 * BSAFE is peculiar here. When IT DER-encodes public keys, it often generates
84 * a publicExponent whose leading bit (m.s. bit in the first byte) is 1. It
85 * reads these fine, of course. But when it DER-encodes the same value in the
86 * private key, it hews to DER rules and prepends a leading zero. If WE
87 * generate a private key with a field with a leading bit set, without the
88 * (technically) required leading zero, BSAFE pukes....but only when parsing
89 * private keys, not public keys. Same field (public exponent), different
90 * requirements for public and private keys. So we're cautious and prepend
91 * a zero if the leading field is one.
93 * This assumes of course that ALL numbers we're dealing with are positive....
95 buf
= (unsigned char *)Malloc(numBytes
+ 1); // extra for possible prepend
97 throw openSslException(CSSMERR_CSP_MEMORY_ERROR
);
99 BN_bn2bin(bn
, buf
+ 1);
101 /* pedantic DER rules for BSAFE - make sure first byte is zero */
107 /* use what BN_bn2bin gave us */
110 snaccInt
.ReSet((char *)bp
, numBytes
);
114 /* estimate size of encoded BigIntegerStr */
115 unsigned sizeofBigInt(
116 BigIntegerStr
&bigInt
)
118 return bigInt
.Len() + 4;
121 /* set up a encoded NULL for AlgorithmIdentifier.parameters, required for RSA */
122 static void nullAlgParams(
123 AlgorithmIdentifier
&snaccAlgId
)
125 snaccAlgId
.parameters
= new AsnAny
;
126 char encodedNull
[2] = {NULLTYPE_TAG_CODE
, 0};
127 CSM_Buffer
*cbuf
= new CSM_Buffer(encodedNull
, 2);
128 snaccAlgId
.parameters
->value
= cbuf
;
132 * int --> BigIntegerStr
134 void snaccIntToBigIntegerStr(
136 BigIntegerStr
&bigInt
)
145 else if(i
> 0x10000) {
155 for(dex
=numChars
-1; dex
>=0; dex
--) {
164 * Replacements for d2i_RSAPublicKey, etc.
166 CSSM_RETURN
RSAPublicKeyDecode(
171 RSAPublicKey snaccPubKey
;
173 CssmData
cData(p
, length
);
175 SC_decodeAsnObj(cData
, snaccPubKey
);
178 return CSSMERR_CSP_INVALID_KEY
;
181 openKey
->n
= bigIntStrToBn(snaccPubKey
.modulus
);
182 openKey
->e
= bigIntStrToBn(snaccPubKey
.publicExponent
);
185 /* FIXME - bad sig? memory? */
186 return CSSMERR_CSP_MEMORY_ERROR
;
191 CSSM_RETURN
RSAPublicKeyEncode(
193 CssmOwnedData
&encodedKey
)
195 /* First convert into a snacc-style public key */
196 RSAPublicKey snaccPubKey
;
199 bnToBigIntStr(openKey
->n
, snaccPubKey
.modulus
);
200 bnToBigIntStr(openKey
->e
, snaccPubKey
.publicExponent
);
204 return CSSMERR_CSP_MEMORY_ERROR
;
207 /* conservative guess for max size of encoded key */
208 unsigned maxSize
= sizeofBigInt(snaccPubKey
.modulus
) +
209 sizeofBigInt(snaccPubKey
.publicExponent
) +
214 SC_encodeAsnObj(snaccPubKey
, encodedKey
, maxSize
);
218 return CSSMERR_CSP_MEMORY_ERROR
;
223 CSSM_RETURN
RSAPrivateKeyDecode(
228 PrivateKeyInfo snaccPrivKeyInfo
;
229 CssmData
cData(p
, length
);
231 SC_decodeAsnObj(cData
, snaccPrivKeyInfo
);
234 return CSSMERR_CSP_INVALID_KEY
;
237 /* verify alg identifier */
238 if(snaccPrivKeyInfo
.privateKeyAlgorithm
== NULL
) {
239 sslSnaccDebug("RSAPrivateKeyDecode: no privateKeyAlgorithm");
240 return CSSMERR_CSP_INVALID_KEY
;
242 if(snaccPrivKeyInfo
.privateKeyAlgorithm
->algorithm
!= rsaEncryption
) {
243 sslSnaccDebug("RSAPrivateKeyDecode: bad privateKeyAlgorithm");
244 return CSSMERR_CSP_ALGID_MISMATCH
;
248 * snaccPrivKeyInfo.privateKey is an octet string which needs
249 * subsequent decoding
251 char *rawOcts
= snaccPrivKeyInfo
.privateKey
;
252 unsigned numBytes
= snaccPrivKeyInfo
.privateKey
.Len();
253 RSAPrivateKey snaccPrivKey
;
254 CssmData
cData2(rawOcts
, numBytes
);
256 SC_decodeAsnObj(cData2
, snaccPrivKey
);
259 sslSnaccDebug("RSAPrivateKeyDecode: bad snaccPrivKeyInfo.privateKey");
260 return CSSMERR_CSP_INVALID_KEY
;
263 /* convert snaccPrivKey fields to RSA key fields */
265 openKey
->version
= snaccPrivKey
.version
;
266 openKey
->n
= bigIntStrToBn(snaccPrivKey
.modulus
);
267 openKey
->e
= bigIntStrToBn(snaccPrivKey
.publicExponent
);
268 openKey
->d
= bigIntStrToBn(snaccPrivKey
.privateExponent
);
269 openKey
->p
= bigIntStrToBn(snaccPrivKey
.prime1
);
270 openKey
->q
= bigIntStrToBn(snaccPrivKey
.prime2
);
271 openKey
->dmp1
= bigIntStrToBn(snaccPrivKey
.exponent1
);
272 openKey
->dmq1
= bigIntStrToBn(snaccPrivKey
.exponent2
);
273 openKey
->iqmp
= bigIntStrToBn(snaccPrivKey
.coefficient
);
276 /* FIXME - bad sig? memory? */
277 return CSSMERR_CSP_MEMORY_ERROR
;
282 CSSM_RETURN
RSAPrivateKeyEncode(
284 CssmOwnedData
&encodedKey
)
286 /* First convert into a snacc-style private key */
287 RSAPrivateKey snaccPrivKey
;
290 snaccPrivKey
.version
= openKey
->version
;
291 bnToBigIntStr(openKey
->n
, snaccPrivKey
.modulus
);
292 bnToBigIntStr(openKey
->e
, snaccPrivKey
.publicExponent
);
293 bnToBigIntStr(openKey
->d
, snaccPrivKey
.privateExponent
);
294 bnToBigIntStr(openKey
->p
, snaccPrivKey
.prime1
);
295 bnToBigIntStr(openKey
->q
, snaccPrivKey
.prime2
);
296 bnToBigIntStr(openKey
->dmp1
, snaccPrivKey
.exponent1
);
297 bnToBigIntStr(openKey
->dmq1
, snaccPrivKey
.exponent2
);
298 bnToBigIntStr(openKey
->iqmp
, snaccPrivKey
.coefficient
);
302 return CSSMERR_CSP_MEMORY_ERROR
;
305 /* conservative guess for max size of encoded key */
306 unsigned maxSize
= sizeofBigInt(snaccPrivKey
.modulus
) +
307 sizeofBigInt(snaccPrivKey
.publicExponent
) +
308 sizeofBigInt(snaccPrivKey
.privateExponent
) +
309 sizeofBigInt(snaccPrivKey
.prime1
) +
310 sizeofBigInt(snaccPrivKey
.prime2
) +
311 sizeofBigInt(snaccPrivKey
.exponent1
) +
312 sizeofBigInt(snaccPrivKey
.exponent2
) +
313 sizeofBigInt(snaccPrivKey
.coefficient
) +
314 64; // includes the to-be-generated algId
318 SC_encodeAsnObj(snaccPrivKey
, encodedKey
, maxSize
);
322 return CSSMERR_CSP_MEMORY_ERROR
;
325 /* that encoding is the privateKey field of a PrivateKeyInfo */
326 PrivateKeyInfo snaccPrivKeyInfo
;
327 snaccPrivKeyInfo
.version
= 0; /* I think.... */
328 snaccPrivKeyInfo
.privateKeyAlgorithm
= new AlgorithmIdentifier
;
329 snaccPrivKeyInfo
.privateKeyAlgorithm
->algorithm
= rsaEncryption
;
330 nullAlgParams(*snaccPrivKeyInfo
.privateKeyAlgorithm
);
331 snaccPrivKeyInfo
.privateKey
.Set((char *)encodedKey
.data(), encodedKey
.length());
333 /* now encode the privateKeyInfo */
336 SC_encodeAsnObj(snaccPrivKeyInfo
, encodedKey
, maxSize
);
340 return CSSMERR_CSP_MEMORY_ERROR
;
346 * Given a message digest and associated algorithm, cook up a PKCS1-style
347 * DigestInfo and return its DER encoding. This is a necessary step for
348 * RSA signature (both generating and verifying) - the output of this
349 * routine is what gets encrypted during signing, and what is expected when
350 * verifying (i.e., decrypting the signature).
352 * A good guess for the length of the output digestInfo is the size of the
353 * key being used to sign/verify. The digest can never be larger than that.
355 CSSM_RETURN
generateDigestInfo(
356 const void *msgDigest
,
358 CSSM_ALGORITHMS digestAlg
, // CSSM_ALGID_SHA1, etc.
359 CssmOwnedData
&encodedInfo
,
360 size_t maxEncodedSize
)
362 if(digestAlg
== CSSM_ALGID_NONE
) {
363 /* special case, no encode, just copy */
364 encodedInfo
.copy(msgDigest
, digestLen
);
369 info
.digest
.Set((char *)msgDigest
, digestLen
);
370 info
.digestAlgorithm
= new DigestAlgorithmIdentifier
;
374 info
.digestAlgorithm
->algorithm
= md5
;
377 info
.digestAlgorithm
->algorithm
= md2
;
379 case CSSM_ALGID_SHA1
:
380 info
.digestAlgorithm
->algorithm
= sha_1
;
383 return CSSMERR_CSP_INVALID_ALGORITHM
;
385 nullAlgParams(*info
.digestAlgorithm
);
387 SC_encodeAsnObj(info
, encodedInfo
, maxEncodedSize
);
390 /* FIXME - bad sig? memory? */
391 return CSSMERR_CSP_MEMORY_ERROR
;
396 unsigned sizeofAsnBits(
399 return (bits
.BitLen() * 8) + 4;
402 unsigned sizeofAsnOcts(
405 return octs
.Len() + 4;
413 /* SNACC DSAAlgorithmId <--> DSA->{p,g,q} */
414 static DSAAlgorithmId
*dsaToSnaccAlgId(
418 DSAAlgorithmId
*algId
= new DSAAlgorithmId
;
420 algId
->algorithm
= dsa_bsafe
;
421 algId
->params
= new DSABsafeParams
;
422 algId
->params
->keySizeInBits
= BN_num_bits(openKey
->p
);
423 bnToBigIntStr(openKey
->p
, algId
->params
->p
);
424 bnToBigIntStr(openKey
->q
, algId
->params
->q
);
425 bnToBigIntStr(openKey
->g
, algId
->params
->g
);
433 static CSSM_RETURN
snaccAlgIdToDsa(
434 DSAAlgorithmId
&algId
,
437 if(algId
.algorithm
!= dsa_bsafe
) {
438 sslSnaccDebug("snaccAlgIdToDsa: bad algorithm");
439 return CSSMERR_CSP_ALGID_MISMATCH
;
441 if(algId
.params
== NULL
) {
442 sslSnaccDebug("snaccAlgIdToDsa: bad params");
443 return CSSMERR_CSP_INVALID_KEY
;
445 openKey
->p
= bigIntStrToBn(algId
.params
->p
);
446 openKey
->q
= bigIntStrToBn(algId
.params
->q
);
447 openKey
->g
= bigIntStrToBn(algId
.params
->g
);
451 static unsigned sizeOfDsaAlg(
452 const DSAAlgorithmId
&algId
)
454 return sizeofBigInt(algId
.params
->p
) +
455 sizeofBigInt(algId
.params
->g
) +
456 sizeofBigInt(algId
.params
->q
) +
460 CSSM_RETURN
DSAPublicKeyDecode(
465 DSAPublicKey snaccPubKey
;
468 CssmData
cData(p
, length
);
470 SC_decodeAsnObj(cData
, snaccPubKey
);
471 rtn
= snaccAlgIdToDsa(*snaccPubKey
.dsaAlg
, openKey
);
476 /* inside of snaccPubKey.publicKey is the DER-encoding of a BigIntegerStr */
477 char *keyOcts
= (char *)snaccPubKey
.publicKey
.BitOcts();
478 CssmData
kData(keyOcts
, (snaccPubKey
.publicKey
.BitLen() + 7) / 8);
479 BigIntegerStr pubKeyOcts
;
480 SC_decodeAsnObj(kData
, pubKeyOcts
);
481 openKey
->pub_key
= bigIntStrToBn(pubKeyOcts
);
483 if(openKey
->pub_key
== NULL
) {
484 return CSSMERR_CSP_INVALID_KEY
;
489 return CSSMERR_CSP_INVALID_KEY
;
493 CSSM_RETURN
DSAPublicKeyEncode(
495 CssmOwnedData
&encodedKey
)
498 /* First convert into a snacc-style public key */
499 DSAPublicKey snaccPubKey
;
501 snaccPubKey
.dsaAlg
= dsaToSnaccAlgId(openKey
);
502 if(snaccPubKey
.dsaAlg
== NULL
) {
503 return CSSMERR_CSP_MEMORY_ERROR
;
507 * publicKey is the DER-encoding of a BigIntegerStr wrapped in
510 BigIntegerStr pubKeyInt
;
511 bnToBigIntStr(openKey
->pub_key
, pubKeyInt
);
512 unsigned maxSize
= sizeofBigInt(pubKeyInt
);
513 SC_encodeAsnObj(pubKeyInt
, encodedKey
, maxSize
);
515 /* that encoding goes into DSAPublicKey.publicKey */
516 snaccPubKey
.publicKey
.Set((char *)encodedKey
.data(), encodedKey
.length() * 8);
518 /* conservative guess for max size of encoded key */
519 maxSize
= sizeOfDsaAlg(*snaccPubKey
.dsaAlg
) +
520 sizeofAsnBits(snaccPubKey
.publicKey
) +
525 SC_encodeAsnObj(snaccPubKey
, encodedKey
, maxSize
);
530 return CSSMERR_CSP_MEMORY_ERROR
;
534 CSSM_RETURN
DSAPrivateKeyDecode(
539 DSAPrivateKey snaccPrivKey
;
542 CssmData
cData(p
, length
);
544 SC_decodeAsnObj(cData
, snaccPrivKey
);
545 openKey
->version
= snaccPrivKey
.version
;
547 rtn
= snaccAlgIdToDsa(*snaccPrivKey
.dsaAlg
, openKey
);
552 /* snaccPrivKey.privateKey is the DER-encoding of a DSAPrivateKeyOcts... */
553 char *keyOcts
= snaccPrivKey
.privateKey
;
554 CssmData
kData(keyOcts
, snaccPrivKey
.privateKey
.Len());
555 DSAPrivateKeyOcts privKeyOcts
;
556 SC_decodeAsnObj(kData
, privKeyOcts
);
558 openKey
->priv_key
= bigIntStrToBn(privKeyOcts
.privateKey
);
559 if(openKey
->priv_key
== NULL
) {
560 return CSSMERR_CSP_INVALID_KEY
;
565 return CSSMERR_CSP_INVALID_KEY
;
569 CSSM_RETURN
DSAPrivateKeyEncode(
571 CssmOwnedData
&encodedKey
)
574 /* First convert into a snacc-style private key */
575 DSAPrivateKey snaccPrivKey
;
577 snaccPrivKey
.version
= openKey
->version
;
578 snaccPrivKey
.dsaAlg
= dsaToSnaccAlgId(openKey
);
579 if(snaccPrivKey
.dsaAlg
== NULL
) {
580 return CSSMERR_CSP_MEMORY_ERROR
;
583 /* DSAPrivateKey.privateKey is the DER-encoding of one of these... */
584 DSAPrivateKeyOcts privKeyOcts
;
585 bnToBigIntStr(openKey
->priv_key
, privKeyOcts
.privateKey
);
587 /* conservative guess for max size of encoded privKey bits */
588 unsigned maxSize
= sizeofBigInt(privKeyOcts
.privateKey
) +
589 10; // includes the to-be-generated algId
592 SC_encodeAsnObj(privKeyOcts
, encodedKey
, maxSize
);
594 /* that encoding goes into DSAPrivateKey.privateKey */
595 snaccPrivKey
.privateKey
.Set((char *)encodedKey
.data(), encodedKey
.length());
597 /* conservative guess for max size of the whole thing */
598 maxSize
= maxSize
+ // what we just did
599 sizeOfDsaAlg(*snaccPrivKey
.dsaAlg
) +
604 SC_encodeAsnObj(snaccPrivKey
, encodedKey
, maxSize
);
609 return CSSMERR_CSP_MEMORY_ERROR
;
613 CSSM_RETURN
DSASigEncode(
615 CssmOwnedData
&encodedSig
)
617 /* First convert into a snacc-style sig */
618 DSASignature snaccSig
;
621 bnToBigIntStr(openSig
->r
, snaccSig
.r
);
622 bnToBigIntStr(openSig
->s
, snaccSig
.s
);
626 return CSSMERR_CSP_MEMORY_ERROR
;
629 /* conservative guess for max size of encoded key */
630 unsigned maxSize
= sizeofBigInt(snaccSig
.r
) +
631 sizeofBigInt(snaccSig
.s
) +
636 SC_encodeAsnObj(snaccSig
, encodedSig
, maxSize
);
640 return CSSMERR_CSP_MEMORY_ERROR
;
645 CSSM_RETURN
DSASigDecode(
650 DSASignature snaccSig
;
652 CssmData
cData((char *)p
, length
);
654 SC_decodeAsnObj(cData
, snaccSig
);
657 return CSSMERR_CSP_INVALID_SIGNATURE
;
660 openSig
->r
= bigIntStrToBn(snaccSig
.r
);
661 openSig
->s
= bigIntStrToBn(snaccSig
.s
);
664 /* FIXME - bad sig? memory? */
665 return CSSMERR_CSP_MEMORY_ERROR
;
670 CSSM_RETURN
DHPrivateKeyDecode(
675 DHPrivateKey snaccPrivKey
;
676 CssmData
cData(p
, length
);
678 SC_decodeAsnObj(cData
, snaccPrivKey
);
681 return CSSMERR_CSP_INVALID_KEY
;
684 /* verify alg identifier */
685 if(snaccPrivKey
.dHOid
!= dhKeyAgreement
) {
686 sslSnaccDebug("DHPrivateKeyDecode: bad privateKeyAlgorithm");
687 return CSSMERR_CSP_ALGID_MISMATCH
;
690 DHParameter
*params
= snaccPrivKey
.params
;
693 sslSnaccDebug("DHPrivateKeyDecode: missing key params");
694 return CSSMERR_CSP_INVALID_KEY
;
697 /* convert snaccPrivKey fields to DH key fields */
699 openKey
->priv_key
= bigIntStrToBn(snaccPrivKey
.secretPart
);
700 openKey
->p
= bigIntStrToBn(params
->prime
);
701 openKey
->g
= bigIntStrToBn(params
->base
);
702 /* TBD - ignore privateValueLength for now */
705 /* FIXME - bad sig? memory? */
706 return CSSMERR_CSP_MEMORY_ERROR
;
711 CSSM_RETURN
DHPrivateKeyEncode(
713 CssmOwnedData
&encodedKey
)
715 /* First convert into a snacc-style private key */
716 DHPrivateKey snaccPrivKey
;
717 snaccPrivKey
.params
= new DHParameter
;
718 DHParameter
*params
= snaccPrivKey
.params
;
721 snaccPrivKey
.dHOid
.Set(dhKeyAgreement_arc
);
722 bnToBigIntStr(openKey
->priv_key
, snaccPrivKey
.secretPart
);
723 bnToBigIntStr(openKey
->p
, params
->prime
);
724 bnToBigIntStr(openKey
->g
, params
->base
);
725 if(openKey
->length
) {
726 /* actually currently not supported */
727 params
->privateValueLength
= new BigIntegerStr();
728 snaccIntToBigIntegerStr(openKey
->length
, *params
->privateValueLength
);
733 return CSSMERR_CSP_MEMORY_ERROR
;
736 /* conservative guess for max size of encoded key */
737 unsigned maxSize
= sizeofBigInt(snaccPrivKey
.secretPart
) +
738 sizeofBigInt(params
->prime
) +
739 sizeofBigInt(params
->base
) +
740 60; // includes dHOid, tags, lenghts
741 if(openKey
->length
) {
742 maxSize
+= sizeofBigInt(*params
->privateValueLength
);
747 SC_encodeAsnObj(snaccPrivKey
, encodedKey
, maxSize
);
751 return CSSMERR_CSP_MEMORY_ERROR
;