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
;
133 * Replacements for d2i_RSAPublicKey, etc.
135 CSSM_RETURN
RSAPublicKeyDecode(
140 RSAPublicKey snaccPubKey
;
142 CssmData
cData(p
, length
);
144 SC_decodeAsnObj(cData
, snaccPubKey
);
147 return CSSMERR_CSP_INVALID_KEY
;
150 openKey
->n
= bigIntStrToBn(snaccPubKey
.modulus
);
151 openKey
->e
= bigIntStrToBn(snaccPubKey
.publicExponent
);
154 /* FIXME - bad sig? memory? */
155 return CSSMERR_CSP_MEMORY_ERROR
;
160 CSSM_RETURN
RSAPublicKeyEncode(
162 CssmOwnedData
&encodedKey
)
164 /* First convert into a snacc-style public key */
165 RSAPublicKey snaccPubKey
;
168 bnToBigIntStr(openKey
->n
, snaccPubKey
.modulus
);
169 bnToBigIntStr(openKey
->e
, snaccPubKey
.publicExponent
);
173 return CSSMERR_CSP_MEMORY_ERROR
;
176 /* conservative guess for max size of encoded key */
177 unsigned maxSize
= sizeofBigInt(snaccPubKey
.modulus
) +
178 sizeofBigInt(snaccPubKey
.publicExponent
) +
183 SC_encodeAsnObj(snaccPubKey
, encodedKey
, maxSize
);
187 return CSSMERR_CSP_MEMORY_ERROR
;
192 CSSM_RETURN
RSAPrivateKeyDecode(
197 PrivateKeyInfo snaccPrivKeyInfo
;
198 CssmData
cData(p
, length
);
200 SC_decodeAsnObj(cData
, snaccPrivKeyInfo
);
203 return CSSMERR_CSP_INVALID_KEY
;
206 /* verify alg identifier */
207 if(snaccPrivKeyInfo
.privateKeyAlgorithm
== NULL
) {
208 sslSnaccDebug("RSAPrivateKeyDecode: no privateKeyAlgorithm");
209 return CSSMERR_CSP_INVALID_KEY
;
211 if(snaccPrivKeyInfo
.privateKeyAlgorithm
->algorithm
!= rsaEncryption
) {
212 sslSnaccDebug("RSAPrivateKeyDecode: bad privateKeyAlgorithm");
213 return CSSMERR_CSP_ALGID_MISMATCH
;
217 * snaccPrivKeyInfo.privateKey is an octet string which needs
218 * subsequent decoding
220 char *rawOcts
= snaccPrivKeyInfo
.privateKey
;
221 unsigned numBytes
= snaccPrivKeyInfo
.privateKey
.Len();
222 RSAPrivateKey snaccPrivKey
;
223 CssmData
cData2(rawOcts
, numBytes
);
225 SC_decodeAsnObj(cData2
, snaccPrivKey
);
228 sslSnaccDebug("RSAPrivateKeyDecode: bad snaccPrivKeyInfo.privateKey");
229 return CSSMERR_CSP_INVALID_KEY
;
232 /* convert snaccPrivKey fields to RSA key fields */
234 openKey
->version
= snaccPrivKey
.version
;
235 openKey
->n
= bigIntStrToBn(snaccPrivKey
.modulus
);
236 openKey
->e
= bigIntStrToBn(snaccPrivKey
.publicExponent
);
237 openKey
->d
= bigIntStrToBn(snaccPrivKey
.privateExponent
);
238 openKey
->p
= bigIntStrToBn(snaccPrivKey
.prime1
);
239 openKey
->q
= bigIntStrToBn(snaccPrivKey
.prime2
);
240 openKey
->dmp1
= bigIntStrToBn(snaccPrivKey
.exponent1
);
241 openKey
->dmq1
= bigIntStrToBn(snaccPrivKey
.exponent2
);
242 openKey
->iqmp
= bigIntStrToBn(snaccPrivKey
.coefficient
);
245 /* FIXME - bad sig? memory? */
246 return CSSMERR_CSP_MEMORY_ERROR
;
251 CSSM_RETURN
RSAPrivateKeyEncode(
253 CssmOwnedData
&encodedKey
)
255 /* First convert into a snacc-style private key */
256 RSAPrivateKey snaccPrivKey
;
259 snaccPrivKey
.version
= openKey
->version
;
260 bnToBigIntStr(openKey
->n
, snaccPrivKey
.modulus
);
261 bnToBigIntStr(openKey
->e
, snaccPrivKey
.publicExponent
);
262 bnToBigIntStr(openKey
->d
, snaccPrivKey
.privateExponent
);
263 bnToBigIntStr(openKey
->p
, snaccPrivKey
.prime1
);
264 bnToBigIntStr(openKey
->q
, snaccPrivKey
.prime2
);
265 bnToBigIntStr(openKey
->dmp1
, snaccPrivKey
.exponent1
);
266 bnToBigIntStr(openKey
->dmq1
, snaccPrivKey
.exponent2
);
267 bnToBigIntStr(openKey
->iqmp
, snaccPrivKey
.coefficient
);
271 return CSSMERR_CSP_MEMORY_ERROR
;
274 /* conservative guess for max size of encoded key */
275 unsigned maxSize
= sizeofBigInt(snaccPrivKey
.modulus
) +
276 sizeofBigInt(snaccPrivKey
.publicExponent
) +
277 sizeofBigInt(snaccPrivKey
.privateExponent
) +
278 sizeofBigInt(snaccPrivKey
.prime1
) +
279 sizeofBigInt(snaccPrivKey
.prime2
) +
280 sizeofBigInt(snaccPrivKey
.exponent1
) +
281 sizeofBigInt(snaccPrivKey
.exponent2
) +
282 sizeofBigInt(snaccPrivKey
.coefficient
) +
283 64; // includes the to-be-generated algId
287 SC_encodeAsnObj(snaccPrivKey
, encodedKey
, maxSize
);
291 return CSSMERR_CSP_MEMORY_ERROR
;
294 /* that encoding is the privateKey field of a PrivateKeyInfo */
295 PrivateKeyInfo snaccPrivKeyInfo
;
296 snaccPrivKeyInfo
.version
= 0; /* I think.... */
297 snaccPrivKeyInfo
.privateKeyAlgorithm
= new AlgorithmIdentifier
;
298 snaccPrivKeyInfo
.privateKeyAlgorithm
->algorithm
= rsaEncryption
;
299 nullAlgParams(*snaccPrivKeyInfo
.privateKeyAlgorithm
);
300 snaccPrivKeyInfo
.privateKey
.Set((char *)encodedKey
.data(), encodedKey
.length());
302 /* now encode the privateKeyInfo */
305 SC_encodeAsnObj(snaccPrivKeyInfo
, encodedKey
, maxSize
);
309 return CSSMERR_CSP_MEMORY_ERROR
;
315 * Given a message digest and associated algorithm, cook up a PKCS1-style
316 * DigestInfo and return its DER encoding. This is a necessary step for
317 * RSA signature (both generating and verifying) - the output of this
318 * routine is what gets encrypted during signing, and what is expected when
319 * verifying (i.e., decrypting the signature).
321 * A good guess for the length of the output digestInfo is the size of the
322 * key being used to sign/verify. The digest can never be larger than that.
324 CSSM_RETURN
generateDigestInfo(
325 const void *msgDigest
,
327 CSSM_ALGORITHMS digestAlg
, // CSSM_ALGID_SHA1, etc.
328 CssmOwnedData
&encodedInfo
,
329 size_t maxEncodedSize
)
331 if(digestAlg
== CSSM_ALGID_NONE
) {
332 /* special case, no encode, just copy */
333 encodedInfo
.copy(msgDigest
, digestLen
);
338 info
.digest
.Set((char *)msgDigest
, digestLen
);
339 info
.digestAlgorithm
= new DigestAlgorithmIdentifier
;
343 info
.digestAlgorithm
->algorithm
= md5
;
346 info
.digestAlgorithm
->algorithm
= md2
;
348 case CSSM_ALGID_SHA1
:
349 info
.digestAlgorithm
->algorithm
= sha_1
;
352 return CSSMERR_CSP_INVALID_ALGORITHM
;
354 nullAlgParams(*info
.digestAlgorithm
);
356 SC_encodeAsnObj(info
, encodedInfo
, maxEncodedSize
);
359 /* FIXME - bad sig? memory? */
360 return CSSMERR_CSP_MEMORY_ERROR
;
365 unsigned sizeofAsnBits(
368 return (bits
.BitLen() * 8) + 4;
371 unsigned sizeofAsnOcts(
374 return octs
.Len() + 4;
382 /* SNACC DSAAlgorithmId <--> DSA->{p,g,q} */
383 static DSAAlgorithmId
*dsaToSnaccAlgId(
387 DSAAlgorithmId
*algId
= new DSAAlgorithmId
;
389 algId
->algorithm
= dsa_bsafe
;
390 algId
->params
= new DSABsafeParams
;
391 algId
->params
->keySizeInBits
= BN_num_bits(openKey
->p
);
392 bnToBigIntStr(openKey
->p
, algId
->params
->p
);
393 bnToBigIntStr(openKey
->q
, algId
->params
->q
);
394 bnToBigIntStr(openKey
->g
, algId
->params
->g
);
402 static CSSM_RETURN
snaccAlgIdToDsa(
403 DSAAlgorithmId
&algId
,
406 if(algId
.algorithm
!= dsa_bsafe
) {
407 sslSnaccDebug("snaccAlgIdToDsa: bad algorithm");
408 return CSSMERR_CSP_ALGID_MISMATCH
;
410 if(algId
.params
== NULL
) {
411 sslSnaccDebug("snaccAlgIdToDsa: bad params");
412 return CSSMERR_CSP_INVALID_KEY
;
414 openKey
->p
= bigIntStrToBn(algId
.params
->p
);
415 openKey
->q
= bigIntStrToBn(algId
.params
->q
);
416 openKey
->g
= bigIntStrToBn(algId
.params
->g
);
420 static unsigned sizeOfDsaAlg(
421 const DSAAlgorithmId
&algId
)
423 return sizeofBigInt(algId
.params
->p
) +
424 sizeofBigInt(algId
.params
->g
) +
425 sizeofBigInt(algId
.params
->q
) +
429 CSSM_RETURN
DSAPublicKeyDecode(
434 DSAPublicKey snaccPubKey
;
437 CssmData
cData(p
, length
);
439 SC_decodeAsnObj(cData
, snaccPubKey
);
440 rtn
= snaccAlgIdToDsa(*snaccPubKey
.dsaAlg
, openKey
);
445 /* inside of snaccPubKey.publicKey is the DER-encoding of a BigIntegerStr */
446 char *keyOcts
= (char *)snaccPubKey
.publicKey
.BitOcts();
447 CssmData
kData(keyOcts
, (snaccPubKey
.publicKey
.BitLen() + 7) / 8);
448 BigIntegerStr pubKeyOcts
;
449 SC_decodeAsnObj(kData
, pubKeyOcts
);
450 openKey
->pub_key
= bigIntStrToBn(pubKeyOcts
);
452 if(openKey
->pub_key
== NULL
) {
453 return CSSMERR_CSP_INVALID_KEY
;
458 return CSSMERR_CSP_INVALID_KEY
;
462 CSSM_RETURN
DSAPublicKeyEncode(
464 CssmOwnedData
&encodedKey
)
467 /* First convert into a snacc-style public key */
468 DSAPublicKey snaccPubKey
;
470 snaccPubKey
.dsaAlg
= dsaToSnaccAlgId(openKey
);
471 if(snaccPubKey
.dsaAlg
== NULL
) {
472 return CSSMERR_CSP_MEMORY_ERROR
;
476 * publicKey is the DER-encoding of a BigIntegerStr wrapped in
479 BigIntegerStr pubKeyInt
;
480 bnToBigIntStr(openKey
->pub_key
, pubKeyInt
);
481 unsigned maxSize
= sizeofBigInt(pubKeyInt
);
482 SC_encodeAsnObj(pubKeyInt
, encodedKey
, maxSize
);
484 /* that encoding goes into DSAPublicKey.publicKey */
485 snaccPubKey
.publicKey
.Set((char *)encodedKey
.data(), encodedKey
.length() * 8);
487 /* conservative guess for max size of encoded key */
488 maxSize
= sizeOfDsaAlg(*snaccPubKey
.dsaAlg
) +
489 sizeofAsnBits(snaccPubKey
.publicKey
) +
494 SC_encodeAsnObj(snaccPubKey
, encodedKey
, maxSize
);
499 return CSSMERR_CSP_MEMORY_ERROR
;
503 CSSM_RETURN
DSAPrivateKeyDecode(
508 DSAPrivateKey snaccPrivKey
;
511 CssmData
cData(p
, length
);
513 SC_decodeAsnObj(cData
, snaccPrivKey
);
514 openKey
->version
= snaccPrivKey
.version
;
516 rtn
= snaccAlgIdToDsa(*snaccPrivKey
.dsaAlg
, openKey
);
521 /* snaccPrivKey.privateKey is the DER-encoding of a DSAPrivateKeyOcts... */
522 char *keyOcts
= snaccPrivKey
.privateKey
;
523 CssmData
kData(keyOcts
, snaccPrivKey
.privateKey
.Len());
524 DSAPrivateKeyOcts privKeyOcts
;
525 SC_decodeAsnObj(kData
, privKeyOcts
);
527 openKey
->priv_key
= bigIntStrToBn(privKeyOcts
.privateKey
);
528 if(openKey
->priv_key
== NULL
) {
529 return CSSMERR_CSP_INVALID_KEY
;
534 return CSSMERR_CSP_INVALID_KEY
;
538 CSSM_RETURN
DSAPrivateKeyEncode(
540 CssmOwnedData
&encodedKey
)
543 /* First convert into a snacc-style private key */
544 DSAPrivateKey snaccPrivKey
;
546 snaccPrivKey
.version
= openKey
->version
;
547 snaccPrivKey
.dsaAlg
= dsaToSnaccAlgId(openKey
);
548 if(snaccPrivKey
.dsaAlg
== NULL
) {
549 return CSSMERR_CSP_MEMORY_ERROR
;
552 /* DSAPrivateKey.privateKey is the DER-encoding of one of these... */
553 DSAPrivateKeyOcts privKeyOcts
;
554 bnToBigIntStr(openKey
->priv_key
, privKeyOcts
.privateKey
);
556 /* conservative guess for max size of encoded privKey bits */
557 unsigned maxSize
= sizeofBigInt(privKeyOcts
.privateKey
) +
558 10; // includes the to-be-generated algId
561 SC_encodeAsnObj(privKeyOcts
, encodedKey
, maxSize
);
563 /* that encoding goes into DSAPrivateKey.privateKey */
564 snaccPrivKey
.privateKey
.Set((char *)encodedKey
.data(), encodedKey
.length());
566 /* conservative guess for max size of the whole thing */
567 maxSize
= maxSize
+ // what we just did
568 sizeOfDsaAlg(*snaccPrivKey
.dsaAlg
) +
573 SC_encodeAsnObj(snaccPrivKey
, encodedKey
, maxSize
);
578 return CSSMERR_CSP_MEMORY_ERROR
;
582 CSSM_RETURN
DSASigEncode(
584 CssmOwnedData
&encodedSig
)
586 /* First convert into a snacc-style sig */
587 DSASignature snaccSig
;
590 bnToBigIntStr(openSig
->r
, snaccSig
.r
);
591 bnToBigIntStr(openSig
->s
, snaccSig
.s
);
595 return CSSMERR_CSP_MEMORY_ERROR
;
598 /* conservative guess for max size of encoded key */
599 unsigned maxSize
= sizeofBigInt(snaccSig
.r
) +
600 sizeofBigInt(snaccSig
.s
) +
605 SC_encodeAsnObj(snaccSig
, encodedSig
, maxSize
);
609 return CSSMERR_CSP_MEMORY_ERROR
;
614 CSSM_RETURN
DSASigDecode(
619 DSASignature snaccSig
;
621 CssmData
cData((char *)p
, length
);
623 SC_decodeAsnObj(cData
, snaccSig
);
626 return CSSMERR_CSP_INVALID_SIGNATURE
;
629 openSig
->r
= bigIntStrToBn(snaccSig
.r
);
630 openSig
->s
= bigIntStrToBn(snaccSig
.s
);
633 /* FIXME - bad sig? memory? */
634 return CSSMERR_CSP_MEMORY_ERROR
;