4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is the Netscape security libraries.
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1994-2000
22 * the Initial Developer. All Rights Reserved.
25 * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
40 /* $Id: secsign.c,v 1.18 2006/06/23 17:01:37 rrelyea%redhat.com Exp $ */
53 struct SGNContextStr
{
57 const SECHashObject
*hashobj
;
58 SECKEYPrivateKey
*key
;
62 SGN_NewContext(SECOidTag alg
, SECKEYPrivateKey
*key
)
65 SECOidTag hashalg
, signalg
;
69 /* OK, map a PKCS #7 hash and encrypt algorithm into
70 * a standard hashing algorithm. Why did we pass in the whole
71 * PKCS #7 algTag if we were just going to change here you might
72 * ask. Well the answer is for some cards we may have to do the
73 * hashing on card. It may not support CKM_RSA_PKCS sign algorithm,
74 * it may just support CKM_RSA_PKCS_WITH_SHA1 and/or CKM_RSA_PKCS_WITH_MD5.
76 /* we have a private key, not a public key, so don't pass it in */
77 rv
= sec_DecodeSigAlg(NULL
, alg
, NULL
, &signalg
, &hashalg
);
78 if (rv
!= SECSuccess
) {
79 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
82 keyType
= seckey_GetKeyType(signalg
);
84 /* verify our key type */
85 if (key
->keyType
!= keyType
&&
86 !((key
->keyType
== dsaKey
) && (keyType
== fortezzaKey
)) &&
87 !((key
->keyType
== fortezzaKey
) && (keyType
== dsaKey
)) ) {
88 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
92 #ifndef NSS_ECC_MORE_THAN_SUITE_B
93 if (key
->keyType
== ecKey
) {
94 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
99 cx
= (SGNContext
*) PORT_ZAlloc(sizeof(SGNContext
));
101 cx
->hashalg
= hashalg
;
102 cx
->signalg
= signalg
;
109 SGN_DestroyContext(SGNContext
*cx
, PRBool freeit
)
112 if (cx
->hashcx
!= NULL
) {
113 (*cx
->hashobj
->destroy
)(cx
->hashcx
, PR_TRUE
);
117 PORT_ZFree(cx
, sizeof(SGNContext
));
123 SGN_Begin(SGNContext
*cx
)
125 if (cx
->hashcx
!= NULL
) {
126 (*cx
->hashobj
->destroy
)(cx
->hashcx
, PR_TRUE
);
130 cx
->hashobj
= HASH_GetHashObjectByOidTag(cx
->hashalg
);
132 return SECFailure
; /* error code is already set */
134 cx
->hashcx
= (*cx
->hashobj
->create
)();
135 if (cx
->hashcx
== NULL
)
138 (*cx
->hashobj
->begin
)(cx
->hashcx
);
143 SGN_Update(SGNContext
*cx
, unsigned char *input
, unsigned inputLen
)
145 if (cx
->hashcx
== NULL
) {
146 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
149 (*cx
->hashobj
->update
)(cx
->hashcx
, input
, inputLen
);
154 SGN_End(SGNContext
*cx
, SECItem
*result
)
156 unsigned char digest
[HASH_LENGTH_MAX
];
160 SECItem digder
, sigitem
;
161 PRArenaPool
*arena
= 0;
162 SECKEYPrivateKey
*privKey
= cx
->key
;
163 SGNDigestInfo
*di
= 0;
168 /* Finish up digest function */
169 if (cx
->hashcx
== NULL
) {
170 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
173 (*cx
->hashobj
->end
)(cx
->hashcx
, digest
, &part1
, sizeof(digest
));
176 if (privKey
->keyType
== rsaKey
) {
178 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
184 /* Construct digest info */
185 di
= SGN_CreateDigestInfo(cx
->hashalg
, digest
, part1
);
191 /* Der encode the digest as a DigestInfo */
192 rv
= DER_Encode(arena
, &digder
, SGNDigestInfoTemplate
, di
);
193 if (rv
!= SECSuccess
) {
197 digder
.data
= digest
;
202 ** Encrypt signature after constructing appropriate PKCS#1 signature
205 signatureLen
= PK11_SignatureLen(privKey
);
206 if (signatureLen
<= 0) {
207 PORT_SetError(SEC_ERROR_INVALID_KEY
);
211 sigitem
.len
= signatureLen
;
212 sigitem
.data
= (unsigned char*) PORT_Alloc(signatureLen
);
214 if (sigitem
.data
== NULL
) {
219 rv
= PK11_Sign(privKey
, &sigitem
, &digder
);
220 if (rv
!= SECSuccess
) {
221 PORT_Free(sigitem
.data
);
226 if ((cx
->signalg
== SEC_OID_ANSIX9_DSA_SIGNATURE
) ||
227 (cx
->signalg
== SEC_OID_ANSIX962_EC_PUBLIC_KEY
)) {
228 /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */
229 rv
= DSAU_EncodeDerSigWithLen(result
, &sigitem
, sigitem
.len
);
230 PORT_Free(sigitem
.data
);
231 if (rv
!= SECSuccess
)
234 result
->len
= sigitem
.len
;
235 result
->data
= sigitem
.data
;
239 SGN_DestroyDigestInfo(di
);
241 PORT_FreeArena(arena
, PR_FALSE
);
246 /************************************************************************/
249 ** Sign a block of data returning in result a bunch of bytes that are the
250 ** signature. Returns zero on success, an error code on failure.
253 SEC_SignData(SECItem
*res
, unsigned char *buf
, int len
,
254 SECKEYPrivateKey
*pk
, SECOidTag algid
)
260 sgn
= SGN_NewContext(algid
, pk
);
266 if (rv
!= SECSuccess
)
269 rv
= SGN_Update(sgn
, buf
, len
);
270 if (rv
!= SECSuccess
)
273 rv
= SGN_End(sgn
, res
);
276 SGN_DestroyContext(sgn
, PR_TRUE
);
280 /************************************************************************/
282 DERTemplate CERTSignedDataTemplate
[] =
285 0, NULL
, sizeof(CERTSignedData
) },
287 offsetof(CERTSignedData
,data
), },
289 offsetof(CERTSignedData
,signatureAlgorithm
),
290 SECAlgorithmIDTemplate
, },
292 offsetof(CERTSignedData
,signature
), },
296 const SEC_ASN1Template CERT_SignedDataTemplate
[] =
299 0, NULL
, sizeof(CERTSignedData
) },
301 offsetof(CERTSignedData
,data
), },
303 offsetof(CERTSignedData
,signatureAlgorithm
),
304 SECOID_AlgorithmIDTemplate
, },
305 { SEC_ASN1_BIT_STRING
,
306 offsetof(CERTSignedData
,signature
), },
310 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedDataTemplate
)
314 SEC_DerSignData(PRArenaPool
*arena
, SECItem
*result
,
315 unsigned char *buf
, int len
, SECKEYPrivateKey
*pk
, SECOidTag algID
)
323 /* XXX We should probably have some asserts here to make sure the key type
327 if (algID
== SEC_OID_UNKNOWN
) {
328 switch(pk
->keyType
) {
330 algID
= SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION
;
333 algID
= SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST
;
336 algID
= SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST
;
339 PORT_SetError(SEC_ERROR_INVALID_KEY
);
344 /* Sign input buffer */
345 rv
= SEC_SignData(&it
, buf
, len
, pk
, algID
);
348 /* Fill out SignedData object */
349 PORT_Memset(&sd
, 0, sizeof(sd
));
352 sd
.signature
.data
= it
.data
;
353 sd
.signature
.len
= it
.len
<< 3; /* convert to bit string */
354 rv
= SECOID_SetAlgorithmID(arena
, &sd
.signatureAlgorithm
, algID
, 0);
357 /* DER encode the signed data object */
358 rv
= DER_Encode(arena
, result
, CERTSignedDataTemplate
, &sd
);
367 SGN_Digest(SECKEYPrivateKey
*privKey
,
368 SECOidTag algtag
, SECItem
*result
, SECItem
*digest
)
373 PRArenaPool
*arena
= 0;
374 SGNDigestInfo
*di
= 0;
379 if (privKey
->keyType
== rsaKey
) {
381 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
387 /* Construct digest info */
388 di
= SGN_CreateDigestInfo(algtag
, digest
->data
, digest
->len
);
394 /* Der encode the digest as a DigestInfo */
395 rv
= DER_Encode(arena
, &digder
, SGNDigestInfoTemplate
, di
);
396 if (rv
!= SECSuccess
) {
400 digder
.data
= digest
->data
;
401 digder
.len
= digest
->len
;
405 ** Encrypt signature after constructing appropriate PKCS#1 signature
408 modulusLen
= PK11_SignatureLen(privKey
);
409 if (modulusLen
<= 0) {
410 PORT_SetError(SEC_ERROR_INVALID_KEY
);
414 result
->len
= modulusLen
;
415 result
->data
= (unsigned char*) PORT_Alloc(modulusLen
);
417 if (result
->data
== NULL
) {
422 rv
= PK11_Sign(privKey
, result
, &digder
);
423 if (rv
!= SECSuccess
) {
424 PORT_Free(result
->data
);
429 SGN_DestroyDigestInfo(di
);
431 PORT_FreeArena(arena
, PR_FALSE
);
437 SEC_GetSignatureAlgorithmOidTag(KeyType keyType
, SECOidTag hashAlgTag
)
439 SECOidTag sigTag
= SEC_OID_UNKNOWN
;
443 switch (hashAlgTag
) {
445 sigTag
= SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION
; break;
447 sigTag
= SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION
; break;
448 case SEC_OID_UNKNOWN
: /* default for RSA if not specified */
450 sigTag
= SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION
; break;
452 sigTag
= SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION
; break;
454 sigTag
= SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION
; break;
456 sigTag
= SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION
; break;
462 switch (hashAlgTag
) {
463 case SEC_OID_UNKNOWN
: /* default for DSA if not specified */
465 sigTag
= SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST
; break;
471 switch (hashAlgTag
) {
472 case SEC_OID_UNKNOWN
: /* default for ECDSA if not specified */
474 sigTag
= SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE
; break;
476 sigTag
= SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE
; break;
478 sigTag
= SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE
; break;
480 sigTag
= SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE
; break;