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