1/*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19/*
20 * RSA_DSA_signature.cpp - openssl-based signature classes.
21 */
22
23#include "RSA_DSA_signature.h"
24#include "RSA_DSA_utils.h"
25#include <stdexcept>
26#include <assert.h>
27#include <security_utilities/debugging.h>
28#include <security_cdsa_utilities/cssmdata.h>
29#include <opensslUtils/opensslUtils.h>
30#include <opensslUtils/opensslAsn1.h>
31
32#define rsaSigDebug(args...) 	secdebug("rsaSig", ## args)
33
34static ModuleNexus<Mutex> gMutex;
35
36RSASigner::~RSASigner()
37{
38	StLock<Mutex> _(gMutex());
39	if(mWeMallocdRsaKey) {
40		assert(mRsaKey != NULL);
41		RSA_free(mRsaKey);
42		mRsaKey = NULL;
43		mWeMallocdRsaKey = false;
44	}
45}
46
47/* reusable init */
48void RSASigner::signerInit(
49	const Context 	&context,
50	bool			isSigning)
51{
52	StLock<Mutex> _(gMutex());
53
54	setIsSigning(isSigning);
55	keyFromContext(context);
56
57	/* optional padding attribute */
58	uint32 padding;
59	bool padPresent = context.getInt(CSSM_ATTRIBUTE_PADDING, padding);
60	if(padPresent) {
61		/* padding specified in context, convert to openssl style */
62		switch(padding) {
63			case CSSM_PADDING_NONE:
64				mPadding = RSA_NO_PADDING;
65				break;
66			case CSSM_PADDING_PKCS1:
67				mPadding = RSA_PKCS1_PADDING;
68				break;
69			default:
70				CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING);
71		}
72	}
73
74	/* optional blinding attribute */
75	uint32 blinding = context.getInt(CSSM_ATTRIBUTE_RSA_BLINDING);
76	if(blinding) {
77		if(RSA_blinding_on(mRsaKey, NULL) <= 0) {
78			/* actually no legit failures */
79			CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
80		}
81	}
82	else {
83		RSA_blinding_off(mRsaKey);
84	}
85
86	setInitFlag(true);
87}
88
89/* sign */
90void RSASigner::sign(
91	const void 		*data,
92	size_t 			dataLen,
93	void			*sig,
94	size_t			*sigLen)	/* IN/OUT */
95{
96	StLock<Mutex> _(gMutex());
97
98	if(mRsaKey == NULL) {
99		CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
100	}
101
102	/* get encoded digest info */
103	CssmAutoData 	encodedInfo(alloc());
104	int irtn = generateDigestInfo(data,
105		dataLen,
106		digestAlg(),
107		encodedInfo,
108		RSA_size(mRsaKey));
109	if(irtn) {
110		rsaSigDebug("***digestInfo error\n");
111		throwOpensslErr(irtn);
112	}
113
114	/* signature := encrypted digest info */
115	irtn = RSA_private_encrypt((int)encodedInfo.length(),
116		(unsigned char *)encodedInfo.data(),
117		(unsigned char *)sig,
118		mRsaKey,
119		mPadding);
120	if(irtn < 0) {
121		throwRsaDsa("RSA_private_encrypt");
122	}
123	if((unsigned)irtn > *sigLen) {
124		rsaSigDebug("RSA_private_encrypt: sig overflow");
125		CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
126	}
127	*sigLen = (unsigned)irtn;
128}
129
130/* verify */
131void RSASigner::verify(
132	const void 		*data,
133	size_t 			dataLen,
134	const void		*sig,
135	size_t			sigLen)
136{
137	StLock<Mutex> _(gMutex());
138
139	const char *op = NULL;
140	bool throwSigVerify = false;
141
142	if(mRsaKey == NULL) {
143		CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
144	}
145
146	/* get encoded digest info */
147	CssmAutoData 	encodedInfo(alloc());
148	int irtn = generateDigestInfo(data,
149		dataLen,
150		digestAlg(),
151		encodedInfo,
152		RSA_size(mRsaKey));
153	if(irtn) {
154		rsaSigDebug("***digestInfo error\n");
155		CssmError::throwMe(/* FIXME */CSSMERR_CSP_INTERNAL_ERROR);
156	}
157
158	/* malloc decrypted signature */
159	unsigned char *decryptSig =
160		(unsigned char *)alloc().malloc(RSA_size(mRsaKey));
161	unsigned decryptSigLen;
162
163	/* signature should be encrypted digest info; decrypt the signature  */
164	irtn = RSA_public_decrypt((int)sigLen,
165		(unsigned char *)sig,
166		decryptSig,
167		mRsaKey,
168		mPadding);
169	if(irtn < 0) {
170		op = "RSA_public_decrypt";
171		throwSigVerify = true;
172		goto abort;
173	}
174	decryptSigLen = (unsigned)irtn;
175	if(decryptSigLen != encodedInfo.length()) {
176		rsaSigDebug("***Decrypted signature length error (exp %ld, got %d)\n",
177			encodedInfo.length(), decryptSigLen);
178		throwSigVerify = true;
179		op = "RSA Sig length check";
180		goto abort;
181	}
182	if(memcmp(decryptSig, encodedInfo.data(), decryptSigLen)) {
183		rsaSigDebug("***Signature miscompare\n");
184		throwSigVerify = true;
185		op = "RSA Sig miscompare";
186		goto abort;
187	}
188	else {
189		irtn = 0;
190	}
191abort:
192	if(decryptSig != NULL) {
193		alloc().free(decryptSig);
194	}
195	if(throwSigVerify) {
196		clearOpensslErrors();
197		CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED);
198	}
199}
200
201/* works for both, but only used for signing */
202size_t RSASigner::maxSigSize()
203{
204	StLock<Mutex> _(gMutex());
205	if(mRsaKey == NULL) {
206		return 0;
207	}
208	return RSA_size(mRsaKey);
209}
210
211/*
212 * obtain key from context, validate, convert to native RSA key
213 */
214void RSASigner::keyFromContext(
215	const Context 	&context)
216{
217	if(initFlag() && (mRsaKey != NULL)) {
218		/* reusing context, OK */
219		return;
220	}
221
222	CSSM_KEYCLASS 	keyClass;
223	CSSM_KEYUSE		keyUse;
224	if(isSigning()) {
225		/* signing with private key */
226		keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
227		keyUse   = CSSM_KEYUSE_SIGN;
228	}
229	else {
230		/* verifying with public key */
231		keyClass = CSSM_KEYCLASS_PUBLIC_KEY;
232		keyUse   = CSSM_KEYUSE_VERIFY;
233	}
234	if(mRsaKey == NULL) {
235		CSSM_DATA label = {0, NULL};
236		mRsaKey = contextToRsaKey(context,
237			mSession,
238			keyClass,
239			keyUse,
240			mWeMallocdRsaKey,
241			label);
242		/* cannot have label param for signing */
243		assert(label.Data == NULL);
244	}
245}
246
247DSASigner::~DSASigner()
248{
249	if(mWeMallocdDsaKey) {
250		assert(mDsaKey != NULL);
251		DSA_free(mDsaKey);
252		mDsaKey = NULL;
253		mWeMallocdDsaKey = false;
254	}
255}
256
257/* reusable init */
258void DSASigner::signerInit(
259	const Context 	&context,
260	bool			isSigning)
261{
262	setIsSigning(isSigning);
263	keyFromContext(context);
264	setInitFlag(true);
265}
266
267/* sign */
268void DSASigner::sign(
269	const void 		*data,
270	size_t 			dataLen,
271	void			*sig,
272	size_t			*sigLen)	/* IN/OUT */
273{
274	if(mDsaKey == NULL) {
275		CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
276	}
277	if(mDsaKey->priv_key == NULL) {
278		CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
279	}
280
281	/* get signature in internal format */
282	DSA_SIG *dsaSig = DSA_do_sign((unsigned char *)data, (int)dataLen, mDsaKey);
283	if(dsaSig == NULL) {
284		throwRsaDsa("DSA_do_sign");
285	}
286
287	/* DER encode the signature */
288	CssmAutoData 	encodedSig(alloc());
289	int irtn = DSASigEncode(dsaSig, encodedSig);
290	if(irtn) {
291		throwRsaDsa("DSASigEncode");
292	}
293	if(encodedSig.length() > *sigLen) {
294		throwRsaDsa("DSA sign overflow");
295	}
296	memmove(sig, encodedSig.data(), encodedSig.length());
297	*sigLen = encodedSig.length();
298	DSA_SIG_free(dsaSig);
299}
300
301/* verify */
302void DSASigner::verify(
303	const void 		*data,
304	size_t 			dataLen,
305	const void		*sig,
306	size_t			sigLen)
307{
308	bool 			throwSigVerify = false;
309	DSA_SIG 		*dsaSig = NULL;
310	CSSM_RETURN		crtn = CSSM_OK;
311	int					irtn;
312
313	if(mDsaKey == NULL) {
314		CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
315	}
316	if(mDsaKey->pub_key == NULL) {
317		CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
318	}
319
320	/* incoming sig is DER encoded....decode into internal format */
321	dsaSig = DSA_SIG_new();
322	crtn = DSASigDecode(dsaSig, sig, (unsigned int)sigLen);
323	if(crtn) {
324		goto abort;
325	}
326
327	irtn = DSA_do_verify((unsigned char *)data, (int)dataLen, dsaSig, mDsaKey);
328	if(irtn != 1) {
329		throwSigVerify = true;
330	}
331
332abort:
333	if(dsaSig != NULL) {
334		DSA_SIG_free(dsaSig);
335	}
336	if(throwSigVerify) {
337		clearOpensslErrors();
338		CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED);
339	}
340	else if(crtn) {
341		CssmError::throwMe(crtn);
342	}
343}
344
345/*
346 * Works for both, but only used for signing.
347 * DSA sig is a sequence of two 160-bit integers.
348 */
349size_t DSASigner::maxSigSize()
350{
351	if(mDsaKey == NULL) {
352		return 0;
353	}
354	size_t outSize;
355	size_t sizeOfOneInt;
356
357	sizeOfOneInt = (160 / 8) +		// the raw contents
358					1 +				// possible leading zero
359					2;				// tag + length (assume DER, not BER)
360	outSize = (2 * sizeOfOneInt) + 5;
361	return outSize;
362}
363
364/*
365 * obtain key from context, validate, convert to native DSA key
366 */
367void DSASigner::keyFromContext(
368	const Context 	&context)
369{
370	if(initFlag() && (mDsaKey != NULL)) {
371		/* reusing context, OK */
372		return;
373	}
374
375	CSSM_KEYCLASS 	keyClass;
376	CSSM_KEYUSE		keyUse;
377	if(isSigning()) {
378		/* signing with private key */
379		keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
380		keyUse   = CSSM_KEYUSE_SIGN;
381	}
382	else {
383		/* verifying with public key */
384		keyClass = CSSM_KEYCLASS_PUBLIC_KEY;
385		keyUse   = CSSM_KEYUSE_VERIFY;
386	}
387	if(mDsaKey == NULL) {
388		mDsaKey = contextToDsaKey(context,
389			mSession,
390			keyClass,
391			keyUse,
392			mWeMallocdDsaKey);
393	}
394}
395