Back to index

lightning-sunbird  0.9+nobinonly
rsawrapr.c
Go to the documentation of this file.
00001 /*
00002  * PKCS#1 encoding and decoding functions.
00003  * This file is believed to contain no code licensed from other parties.
00004  *
00005  * ***** BEGIN LICENSE BLOCK *****
00006  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00007  *
00008  * The contents of this file are subject to the Mozilla Public License Version
00009  * 1.1 (the "License"); you may not use this file except in compliance with
00010  * the License. You may obtain a copy of the License at
00011  * http://www.mozilla.org/MPL/
00012  *
00013  * Software distributed under the License is distributed on an "AS IS" basis,
00014  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00015  * for the specific language governing rights and limitations under the
00016  * License.
00017  *
00018  * The Original Code is the Netscape security libraries.
00019  *
00020  * The Initial Developer of the Original Code is
00021  * Netscape Communications Corporation.
00022  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00023  * the Initial Developer. All Rights Reserved.
00024  *
00025  * Contributor(s):
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either the GNU General Public License Version 2 or later (the "GPL"), or
00029  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 /* $Id: rsawrapr.c,v 1.8.30.2 2006/07/31 18:17:14 wtchang%redhat.com Exp $ */
00041 
00042 #include "blapi.h"
00043 #include "softoken.h"
00044 #include "sechash.h"
00045 
00046 #include "lowkeyi.h"
00047 #include "secerr.h"
00048 
00049 #define RSA_BLOCK_MIN_PAD_LEN             8
00050 #define RSA_BLOCK_FIRST_OCTET             0x00
00051 #define RSA_BLOCK_PRIVATE0_PAD_OCTET      0x00
00052 #define RSA_BLOCK_PRIVATE_PAD_OCTET       0xff
00053 #define RSA_BLOCK_AFTER_PAD_OCTET  0x00
00054 
00055 #define OAEP_SALT_LEN              8
00056 #define OAEP_PAD_LEN        8
00057 #define OAEP_PAD_OCTET             0x00
00058 
00059 #define FLAT_BUFSIZE 512    /* bytes to hold flattened SHA1Context. */
00060 
00061 static SHA1Context *
00062 SHA1_CloneContext(SHA1Context *original)
00063 {
00064     SHA1Context *  clone    = NULL;
00065     unsigned char *pBuf;
00066     int            sha1ContextSize = SHA1_FlattenSize(original);
00067     SECStatus      frv;
00068     unsigned char  buf[FLAT_BUFSIZE];
00069 
00070     PORT_Assert(sizeof buf >= sha1ContextSize);
00071     if (sizeof buf >= sha1ContextSize) {
00072        pBuf = buf;
00073     } else {
00074         pBuf = PORT_Alloc(sha1ContextSize);
00075        if (!pBuf)
00076            goto done;
00077     }
00078 
00079     frv = SHA1_Flatten(original, pBuf);
00080     if (frv == SECSuccess) {
00081        clone = SHA1_Resurrect(pBuf, NULL);
00082        memset(pBuf, 0, sha1ContextSize);
00083     }
00084 done:
00085     if (pBuf != buf)
00086        PORT_Free(pBuf);
00087     return clone;
00088 }
00089 
00090 /*
00091  * Modify data by XORing it with a special hash of salt.
00092  */
00093 static SECStatus
00094 oaep_xor_with_h1(unsigned char *data, unsigned int datalen,
00095                unsigned char *salt, unsigned int saltlen)
00096 {
00097     SHA1Context *sha1cx;
00098     unsigned char *dp, *dataend;
00099     unsigned char end_octet;
00100 
00101     sha1cx = SHA1_NewContext();
00102     if (sha1cx == NULL) {
00103        return SECFailure;
00104     }
00105 
00106     /*
00107      * Get a hash of salt started; we will use it several times,
00108      * adding in a different end octet (x00, x01, x02, ...).
00109      */
00110     SHA1_Begin (sha1cx);
00111     SHA1_Update (sha1cx, salt, saltlen);
00112     end_octet = 0;
00113 
00114     dp = data;
00115     dataend = data + datalen;
00116 
00117     while (dp < dataend) {
00118        SHA1Context *sha1cx_h1;
00119        unsigned int sha1len, sha1off;
00120        unsigned char sha1[SHA1_LENGTH];
00121 
00122        /*
00123         * Create hash of (salt || end_octet)
00124         */
00125        sha1cx_h1 = SHA1_CloneContext (sha1cx);
00126        SHA1_Update (sha1cx_h1, &end_octet, 1);
00127        SHA1_End (sha1cx_h1, sha1, &sha1len, sizeof(sha1));
00128        SHA1_DestroyContext (sha1cx_h1, PR_TRUE);
00129        PORT_Assert (sha1len == SHA1_LENGTH);
00130 
00131        /*
00132         * XOR that hash with the data.
00133         * When we have fewer than SHA1_LENGTH octets of data
00134         * left to xor, use just the low-order ones of the hash.
00135         */
00136        sha1off = 0;
00137        if ((dataend - dp) < SHA1_LENGTH)
00138            sha1off = SHA1_LENGTH - (dataend - dp);
00139        while (sha1off < SHA1_LENGTH)
00140            *dp++ ^= sha1[sha1off++];
00141 
00142        /*
00143         * Bump for next hash chunk.
00144         */
00145        end_octet++;
00146     }
00147 
00148     return SECSuccess;
00149 }
00150 
00151 /*
00152  * Modify salt by XORing it with a special hash of data.
00153  */
00154 static SECStatus
00155 oaep_xor_with_h2(unsigned char *salt, unsigned int saltlen,
00156                unsigned char *data, unsigned int datalen)
00157 {
00158     unsigned char sha1[SHA1_LENGTH];
00159     unsigned char *psalt, *psha1, *saltend;
00160     SECStatus rv;
00161 
00162     /*
00163      * Create a hash of data.
00164      */
00165     rv = SHA1_HashBuf (sha1, data, datalen);
00166     if (rv != SECSuccess) {
00167        return rv;
00168     }
00169 
00170     /*
00171      * XOR the low-order octets of that hash with salt.
00172      */
00173     PORT_Assert (saltlen <= SHA1_LENGTH);
00174     saltend = salt + saltlen;
00175     psalt = salt;
00176     psha1 = sha1 + SHA1_LENGTH - saltlen;
00177     while (psalt < saltend) {
00178        *psalt++ ^= *psha1++;
00179     }
00180 
00181     return SECSuccess;
00182 }
00183 
00184 /*
00185  * Format one block of data for public/private key encryption using
00186  * the rules defined in PKCS #1.
00187  */
00188 static unsigned char *
00189 rsa_FormatOneBlock(unsigned modulusLen, RSA_BlockType blockType,
00190                  SECItem *data)
00191 {
00192     unsigned char *block;
00193     unsigned char *bp;
00194     int padLen;
00195     int i;
00196     SECStatus rv;
00197 
00198     block = (unsigned char *) PORT_Alloc(modulusLen);
00199     if (block == NULL)
00200        return NULL;
00201 
00202     bp = block;
00203 
00204     /*
00205      * All RSA blocks start with two octets:
00206      * 0x00 || BlockType
00207      */
00208     *bp++ = RSA_BLOCK_FIRST_OCTET;
00209     *bp++ = (unsigned char) blockType;
00210 
00211     switch (blockType) {
00212 
00213       /*
00214        * Blocks intended for private-key operation.
00215        */
00216       case RSA_BlockPrivate0: /* essentially unused */
00217       case RSA_BlockPrivate:        /* preferred method */
00218        /*
00219         * 0x00 || BT || Pad || 0x00 || ActualData
00220         *   1      1   padLen    1      data->len
00221         * Pad is either all 0x00 or all 0xff bytes, depending on blockType.
00222         */
00223        padLen = modulusLen - data->len - 3;
00224        PORT_Assert (padLen >= RSA_BLOCK_MIN_PAD_LEN);
00225        if (padLen < RSA_BLOCK_MIN_PAD_LEN) {
00226            PORT_Free (block);
00227            return NULL;
00228        }
00229        PORT_Memset (bp,
00230                  blockType == RSA_BlockPrivate0
00231                      ? RSA_BLOCK_PRIVATE0_PAD_OCTET
00232                      : RSA_BLOCK_PRIVATE_PAD_OCTET,
00233                  padLen);
00234        bp += padLen;
00235        *bp++ = RSA_BLOCK_AFTER_PAD_OCTET;
00236        PORT_Memcpy (bp, data->data, data->len);
00237        break;
00238 
00239       /*
00240        * Blocks intended for public-key operation.
00241        */
00242       case RSA_BlockPublic:
00243 
00244        /*
00245         * 0x00 || BT || Pad || 0x00 || ActualData
00246         *   1      1   padLen    1      data->len
00247         * Pad is all non-zero random bytes.
00248         */
00249        padLen = modulusLen - data->len - 3;
00250        PORT_Assert (padLen >= RSA_BLOCK_MIN_PAD_LEN);
00251        if (padLen < RSA_BLOCK_MIN_PAD_LEN) {
00252            PORT_Free (block);
00253            return NULL;
00254        }
00255        for (i = 0; i < padLen; i++) {
00256            /* Pad with non-zero random data. */
00257            do {
00258               rv = RNG_GenerateGlobalRandomBytes(bp + i, 1);
00259            } while (rv == SECSuccess && bp[i] == RSA_BLOCK_AFTER_PAD_OCTET);
00260            if (rv != SECSuccess) {
00261               sftk_fatalError = PR_TRUE;
00262               PORT_Free (block);
00263               return NULL;
00264            }
00265        }
00266        bp += padLen;
00267        *bp++ = RSA_BLOCK_AFTER_PAD_OCTET;
00268        PORT_Memcpy (bp, data->data, data->len);
00269 
00270        break;
00271 
00272       /*
00273        * Blocks intended for public-key operation, using
00274        * Optimal Asymmetric Encryption Padding (OAEP).
00275        */
00276       case RSA_BlockOAEP:
00277        /*
00278         * 0x00 || BT || Modified2(Salt) || Modified1(PaddedData)
00279         *   1      1     OAEP_SALT_LEN     OAEP_PAD_LEN + data->len [+ N]
00280         *
00281         * where:
00282         *   PaddedData is "Pad1 || ActualData [|| Pad2]"
00283         *   Salt is random data.
00284         *   Pad1 is all zeros.
00285         *   Pad2, if present, is random data.
00286         *   (The "modified" fields are all the same length as the original
00287         * unmodified values; they are just xor'd with other values.)
00288         *
00289         *   Modified1 is an XOR of PaddedData with a special octet
00290         * string constructed of iterated hashing of Salt (see below).
00291         *   Modified2 is an XOR of Salt with the low-order octets of
00292         * the hash of Modified1 (see farther below ;-).
00293         *
00294         * Whew!
00295         */
00296 
00297 
00298        /*
00299         * Salt
00300         */
00301        rv = RNG_GenerateGlobalRandomBytes(bp, OAEP_SALT_LEN);
00302        if (rv != SECSuccess) {
00303            sftk_fatalError = PR_TRUE;
00304            PORT_Free (block);
00305            return NULL;
00306        }
00307        bp += OAEP_SALT_LEN;
00308 
00309        /*
00310         * Pad1
00311         */
00312        PORT_Memset (bp, OAEP_PAD_OCTET, OAEP_PAD_LEN);
00313        bp += OAEP_PAD_LEN;
00314 
00315        /*
00316         * Data
00317         */
00318        PORT_Memcpy (bp, data->data, data->len);
00319        bp += data->len;
00320 
00321        /*
00322         * Pad2
00323         */
00324        if (bp < (block + modulusLen)) {
00325            rv = RNG_GenerateGlobalRandomBytes(bp, block - bp + modulusLen);
00326            if (rv != SECSuccess) {
00327               sftk_fatalError = PR_TRUE;
00328               PORT_Free (block);
00329               return NULL;
00330            }
00331        }
00332 
00333        /*
00334         * Now we have the following:
00335         * 0x00 || BT || Salt || PaddedData
00336         * (From this point on, "Pad1 || Data [|| Pad2]" is treated
00337         * as the one entity PaddedData.)
00338         *
00339         * We need to turn PaddedData into Modified1.
00340         */
00341        if (oaep_xor_with_h1(block + 2 + OAEP_SALT_LEN,
00342                           modulusLen - 2 - OAEP_SALT_LEN,
00343                           block + 2, OAEP_SALT_LEN) != SECSuccess) {
00344            PORT_Free (block);
00345            return NULL;
00346        }
00347 
00348        /*
00349         * Now we have:
00350         * 0x00 || BT || Salt || Modified1(PaddedData)
00351         *
00352         * The remaining task is to turn Salt into Modified2.
00353         */
00354        if (oaep_xor_with_h2(block + 2, OAEP_SALT_LEN,
00355                           block + 2 + OAEP_SALT_LEN,
00356                           modulusLen - 2 - OAEP_SALT_LEN) != SECSuccess) {
00357            PORT_Free (block);
00358            return NULL;
00359        }
00360 
00361        break;
00362 
00363       default:
00364        PORT_Assert (0);
00365        PORT_Free (block);
00366        return NULL;
00367     }
00368 
00369     return block;
00370 }
00371 
00372 static SECStatus
00373 rsa_FormatBlock(SECItem *result, unsigned modulusLen,
00374               RSA_BlockType blockType, SECItem *data)
00375 {
00376     /*
00377      * XXX For now assume that the data length fits in a single
00378      * XXX encryption block; the ASSERTs below force this.
00379      * XXX To fix it, each case will have to loop over chunks whose
00380      * XXX lengths satisfy the assertions, until all data is handled.
00381      * XXX (Unless RSA has more to say about how to handle data
00382      * XXX which does not fit in a single encryption block?)
00383      * XXX And I do not know what the result is supposed to be,
00384      * XXX so the interface to this function may need to change
00385      * XXX to allow for returning multiple blocks, if they are
00386      * XXX not wanted simply concatenated one after the other.
00387      */
00388 
00389     switch (blockType) {
00390       case RSA_BlockPrivate0:
00391       case RSA_BlockPrivate:
00392       case RSA_BlockPublic:
00393        /*
00394         * 0x00 || BT || Pad || 0x00 || ActualData
00395         *
00396         * The "3" below is the first octet + the second octet + the 0x00
00397         * octet that always comes just before the ActualData.
00398         */
00399        PORT_Assert (data->len <= (modulusLen - (3 + RSA_BLOCK_MIN_PAD_LEN)));
00400 
00401        result->data = rsa_FormatOneBlock(modulusLen, blockType, data);
00402        if (result->data == NULL) {
00403            result->len = 0;
00404            return SECFailure;
00405        }
00406        result->len = modulusLen;
00407 
00408        break;
00409 
00410       case RSA_BlockOAEP:
00411        /*
00412         * 0x00 || BT || M1(Salt) || M2(Pad1||ActualData[||Pad2])
00413         *
00414         * The "2" below is the first octet + the second octet.
00415         * (The other fields do not contain the clear values, but are
00416         * the same length as the clear values.)
00417         */
00418        PORT_Assert (data->len <= (modulusLen - (2 + OAEP_SALT_LEN
00419                                            + OAEP_PAD_LEN)));
00420 
00421        result->data = rsa_FormatOneBlock(modulusLen, blockType, data);
00422        if (result->data == NULL) {
00423            result->len = 0;
00424            return SECFailure;
00425        }
00426        result->len = modulusLen;
00427 
00428        break;
00429 
00430       case RSA_BlockRaw:
00431        /*
00432         * Pad || ActualData
00433         * Pad is zeros. The application is responsible for recovering
00434         * the actual data.
00435         */
00436        if (data->len > modulusLen ) {
00437            return SECFailure;
00438        }
00439        result->data = (unsigned char*)PORT_ZAlloc(modulusLen);
00440        result->len = modulusLen;
00441        PORT_Memcpy(result->data+(modulusLen-data->len),data->data,data->len);
00442        break;
00443 
00444       default:
00445        PORT_Assert (0);
00446        result->data = NULL;
00447        result->len = 0;
00448        return SECFailure;
00449     }
00450 
00451     return SECSuccess;
00452 }
00453 
00454 /* XXX Doesn't set error code */
00455 SECStatus
00456 RSA_Sign(NSSLOWKEYPrivateKey *key, 
00457          unsigned char *      output, 
00458         unsigned int *       output_len,
00459          unsigned int         maxOutputLen, 
00460         unsigned char *      input, 
00461         unsigned int         input_len)
00462 {
00463     SECStatus     rv          = SECSuccess;
00464     unsigned int  modulus_len = nsslowkey_PrivateModulusLen(key);
00465     SECItem       formatted;
00466     SECItem       unformatted;
00467 
00468     if (maxOutputLen < modulus_len) 
00469        return SECFailure;
00470     PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
00471     if (key->keyType != NSSLOWKEYRSAKey)
00472        return SECFailure;
00473 
00474     unformatted.len  = input_len;
00475     unformatted.data = input;
00476     formatted.data   = NULL;
00477     rv = rsa_FormatBlock(&formatted, modulus_len, RSA_BlockPrivate,
00478                       &unformatted);
00479     if (rv != SECSuccess) 
00480        goto done;
00481 
00482     rv = RSA_PrivateKeyOpDoubleChecked(&key->u.rsa, output, formatted.data);
00483     if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
00484        sftk_fatalError = PR_TRUE;
00485     }
00486     *output_len = modulus_len;
00487 
00488     goto done;
00489 
00490 done:
00491     if (formatted.data != NULL) 
00492        PORT_ZFree(formatted.data, modulus_len);
00493     return rv;
00494 }
00495 
00496 /* XXX Doesn't set error code */
00497 SECStatus
00498 RSA_CheckSign(NSSLOWKEYPublicKey *key,
00499               unsigned char *     sign, 
00500              unsigned int        sign_len, 
00501              unsigned char *     hash, 
00502              unsigned int        hash_len)
00503 {
00504     SECStatus       rv;
00505     unsigned int    modulus_len = nsslowkey_PublicModulusLen(key);
00506     unsigned int    i;
00507     unsigned char * buffer;
00508 
00509     modulus_len = nsslowkey_PublicModulusLen(key);
00510     if (sign_len != modulus_len) 
00511        goto failure;
00512     /*
00513      * 0x00 || BT || Pad || 0x00 || ActualData
00514      *
00515      * The "3" below is the first octet + the second octet + the 0x00
00516      * octet that always comes just before the ActualData.
00517      */
00518     if (hash_len > modulus_len - (3 + RSA_BLOCK_MIN_PAD_LEN)) 
00519        goto failure;
00520     PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
00521     if (key->keyType != NSSLOWKEYRSAKey)
00522        goto failure;
00523 
00524     buffer = (unsigned char *)PORT_Alloc(modulus_len + 1);
00525     if (!buffer)
00526        goto failure;
00527 
00528     rv = RSA_PublicKeyOp(&key->u.rsa, buffer, sign);
00529     if (rv != SECSuccess)
00530        goto loser;
00531 
00532     /*
00533      * check the padding that was used
00534      */
00535     if (buffer[0] != 0 || buffer[1] != 1) 
00536        goto loser;
00537     for (i = 2; i < modulus_len - hash_len - 1; i++) {
00538        if (buffer[i] != 0xff) 
00539            goto loser;
00540     }
00541     if (buffer[i] != 0) 
00542        goto loser;
00543 
00544     /*
00545      * make sure we get the same results
00546      */
00547     if (PORT_Memcmp(buffer + modulus_len - hash_len, hash, hash_len) != 0)
00548        goto loser;
00549 
00550     PORT_Free(buffer);
00551     return SECSuccess;
00552 
00553 loser:
00554     PORT_Free(buffer);
00555 failure:
00556     return SECFailure;
00557 }
00558 
00559 /* XXX Doesn't set error code */
00560 SECStatus
00561 RSA_CheckSignRecover(NSSLOWKEYPublicKey *key,
00562                      unsigned char *     data,
00563                      unsigned int *      data_len, 
00564                    unsigned int        max_output_len, 
00565                    unsigned char *     sign,
00566                    unsigned int        sign_len)
00567 {
00568     SECStatus       rv;
00569     unsigned int    modulus_len = nsslowkey_PublicModulusLen(key);
00570     unsigned int    i;
00571     unsigned char * buffer;
00572 
00573     if (sign_len != modulus_len) 
00574        goto failure;
00575     PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
00576     if (key->keyType != NSSLOWKEYRSAKey)
00577        goto failure;
00578 
00579     buffer = (unsigned char *)PORT_Alloc(modulus_len + 1);
00580     if (!buffer)
00581        goto failure;
00582 
00583     rv = RSA_PublicKeyOp(&key->u.rsa, buffer, sign);
00584     if (rv != SECSuccess)
00585        goto loser;
00586     *data_len = 0;
00587 
00588     /*
00589      * check the padding that was used
00590      */
00591     if (buffer[0] != 0 || buffer[1] != 1) 
00592        goto loser;
00593     for (i = 2; i < modulus_len; i++) {
00594        if (buffer[i] == 0) {
00595            *data_len = modulus_len - i - 1;
00596            break;
00597        }
00598        if (buffer[i] != 0xff) 
00599            goto loser;
00600     }
00601     if (*data_len == 0) 
00602        goto loser;
00603     if (*data_len > max_output_len) 
00604        goto loser;
00605 
00606     /*
00607      * make sure we get the same results
00608      */
00609     PORT_Memcpy(data,buffer + modulus_len - *data_len, *data_len);
00610 
00611     PORT_Free(buffer);
00612     return SECSuccess;
00613 
00614 loser:
00615     PORT_Free(buffer);
00616 failure:
00617     return SECFailure;
00618 }
00619 
00620 /* XXX Doesn't set error code */
00621 SECStatus
00622 RSA_EncryptBlock(NSSLOWKEYPublicKey *key, 
00623                  unsigned char *     output, 
00624                unsigned int *      output_len,
00625                  unsigned int        max_output_len, 
00626                unsigned char *     input, 
00627                unsigned int        input_len)
00628 {
00629     SECStatus     rv;
00630     unsigned int  modulus_len = nsslowkey_PublicModulusLen(key);
00631     SECItem       formatted;
00632     SECItem       unformatted;
00633 
00634     formatted.data = NULL;
00635     if (max_output_len < modulus_len) 
00636        goto failure;
00637     PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
00638     if (key->keyType != NSSLOWKEYRSAKey)
00639        goto failure;
00640 
00641     unformatted.len  = input_len;
00642     unformatted.data = input;
00643     formatted.data   = NULL;
00644     rv = rsa_FormatBlock(&formatted, modulus_len, RSA_BlockPublic,
00645                       &unformatted);
00646     if (rv != SECSuccess) 
00647        goto failure;
00648 
00649     rv = RSA_PublicKeyOp(&key->u.rsa, output, formatted.data);
00650     if (rv != SECSuccess) 
00651        goto failure;
00652 
00653     PORT_ZFree(formatted.data, modulus_len);
00654     *output_len = modulus_len;
00655     return SECSuccess;
00656 
00657 failure:
00658     if (formatted.data != NULL) 
00659        PORT_ZFree(formatted.data, modulus_len);
00660     return SECFailure;
00661 }
00662 
00663 /* XXX Doesn't set error code */
00664 SECStatus
00665 RSA_DecryptBlock(NSSLOWKEYPrivateKey *key, 
00666                  unsigned char *      output, 
00667                unsigned int *       output_len,
00668                  unsigned int         max_output_len, 
00669                unsigned char *      input, 
00670                unsigned int         input_len)
00671 {
00672     SECStatus       rv;
00673     unsigned int    modulus_len = nsslowkey_PrivateModulusLen(key);
00674     unsigned int    i;
00675     unsigned char * buffer;
00676 
00677     PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
00678     if (key->keyType != NSSLOWKEYRSAKey)
00679        goto failure;
00680     if (input_len != modulus_len)
00681        goto failure;
00682 
00683     buffer = (unsigned char *)PORT_Alloc(modulus_len + 1);
00684     if (!buffer)
00685        goto failure;
00686 
00687     rv = RSA_PrivateKeyOp(&key->u.rsa, buffer, input);
00688     if (rv != SECSuccess) {
00689        if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
00690            sftk_fatalError = PR_TRUE;
00691        }
00692        goto loser;
00693     }
00694 
00695     if (buffer[0] != 0 || buffer[1] != 2) 
00696        goto loser;
00697     *output_len = 0;
00698     for (i = 2; i < modulus_len; i++) {
00699        if (buffer[i] == 0) {
00700            *output_len = modulus_len - i - 1;
00701            break;
00702        }
00703     }
00704     if (*output_len == 0) 
00705        goto loser;
00706     if (*output_len > max_output_len) 
00707        goto loser;
00708 
00709     PORT_Memcpy(output, buffer + modulus_len - *output_len, *output_len);
00710 
00711     PORT_Free(buffer);
00712     return SECSuccess;
00713 
00714 loser:
00715     PORT_Free(buffer);
00716 failure:
00717     return SECFailure;
00718 }
00719 
00720 /* XXX Doesn't set error code */
00721 /*
00722  * added to make pkcs #11 happy
00723  *   RAW is RSA_X_509
00724  */
00725 SECStatus
00726 RSA_SignRaw(NSSLOWKEYPrivateKey *key, 
00727             unsigned char *      output, 
00728            unsigned int *       output_len,
00729             unsigned int         maxOutputLen, 
00730            unsigned char *      input, 
00731            unsigned int         input_len)
00732 {
00733     SECStatus    rv          = SECSuccess;
00734     unsigned int modulus_len = nsslowkey_PrivateModulusLen(key);
00735     SECItem      formatted;
00736     SECItem      unformatted;
00737 
00738     if (maxOutputLen < modulus_len) 
00739        return SECFailure;
00740     PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
00741     if (key->keyType != NSSLOWKEYRSAKey)
00742        return SECFailure;
00743 
00744     unformatted.len  = input_len;
00745     unformatted.data = input;
00746     formatted.data   = NULL;
00747     rv = rsa_FormatBlock(&formatted, modulus_len, RSA_BlockRaw, &unformatted);
00748     if (rv != SECSuccess) 
00749        goto done;
00750 
00751     rv = RSA_PrivateKeyOpDoubleChecked(&key->u.rsa, output, formatted.data);
00752     if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
00753        sftk_fatalError = PR_TRUE;
00754     }
00755     *output_len = modulus_len;
00756 
00757 done:
00758     if (formatted.data != NULL) 
00759        PORT_ZFree(formatted.data, modulus_len);
00760     return rv;
00761 }
00762 
00763 /* XXX Doesn't set error code */
00764 SECStatus
00765 RSA_CheckSignRaw(NSSLOWKEYPublicKey *key,
00766                  unsigned char *     sign, 
00767                unsigned int        sign_len, 
00768                unsigned char *     hash, 
00769                unsigned int        hash_len)
00770 {
00771     SECStatus       rv;
00772     unsigned int    modulus_len = nsslowkey_PublicModulusLen(key);
00773     unsigned char * buffer;
00774 
00775     if (sign_len != modulus_len) 
00776        goto failure;
00777     if (hash_len > modulus_len) 
00778        goto failure;
00779     PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
00780     if (key->keyType != NSSLOWKEYRSAKey)
00781        goto failure;
00782 
00783     buffer = (unsigned char *)PORT_Alloc(modulus_len + 1);
00784     if (!buffer)
00785        goto failure;
00786 
00787     rv = RSA_PublicKeyOp(&key->u.rsa, buffer, sign);
00788     if (rv != SECSuccess)
00789        goto loser;
00790 
00791     /*
00792      * make sure we get the same results
00793      */
00794     /* NOTE: should we verify the leading zeros? */
00795     if (PORT_Memcmp(buffer + (modulus_len-hash_len), hash, hash_len) != 0)
00796        goto loser;
00797 
00798     PORT_Free(buffer);
00799     return SECSuccess;
00800 
00801 loser:
00802     PORT_Free(buffer);
00803 failure:
00804     return SECFailure;
00805 }
00806 
00807 /* XXX Doesn't set error code */
00808 SECStatus
00809 RSA_CheckSignRecoverRaw(NSSLOWKEYPublicKey *key,
00810                         unsigned char *     data,
00811                         unsigned int *      data_len, 
00812                      unsigned int        max_output_len, 
00813                      unsigned char *     sign,
00814                      unsigned int        sign_len)
00815 {
00816     SECStatus      rv;
00817     unsigned int   modulus_len = nsslowkey_PublicModulusLen(key);
00818 
00819     if (sign_len != modulus_len) 
00820        goto failure;
00821     if (max_output_len < modulus_len) 
00822        goto failure;
00823     PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
00824     if (key->keyType != NSSLOWKEYRSAKey)
00825        goto failure;
00826 
00827     rv = RSA_PublicKeyOp(&key->u.rsa, data, sign);
00828     if (rv != SECSuccess)
00829        goto failure;
00830 
00831     *data_len = modulus_len;
00832     return SECSuccess;
00833 
00834 failure:
00835     return SECFailure;
00836 }
00837 
00838 
00839 /* XXX Doesn't set error code */
00840 SECStatus
00841 RSA_EncryptRaw(NSSLOWKEYPublicKey *key, 
00842               unsigned char *     output, 
00843               unsigned int *      output_len,
00844                unsigned int        max_output_len, 
00845               unsigned char *     input, 
00846               unsigned int        input_len)
00847 {
00848     SECStatus rv;
00849     unsigned int  modulus_len = nsslowkey_PublicModulusLen(key);
00850     SECItem       formatted;
00851     SECItem       unformatted;
00852 
00853     formatted.data = NULL;
00854     if (max_output_len < modulus_len) 
00855        goto failure;
00856     PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
00857     if (key->keyType != NSSLOWKEYRSAKey)
00858        goto failure;
00859 
00860     unformatted.len  = input_len;
00861     unformatted.data = input;
00862     formatted.data   = NULL;
00863     rv = rsa_FormatBlock(&formatted, modulus_len, RSA_BlockRaw, &unformatted);
00864     if (rv != SECSuccess)
00865        goto failure;
00866 
00867     rv = RSA_PublicKeyOp(&key->u.rsa, output, formatted.data);
00868     if (rv != SECSuccess) 
00869        goto failure;
00870 
00871     PORT_ZFree(formatted.data, modulus_len);
00872     *output_len = modulus_len;
00873     return SECSuccess;
00874 
00875 failure:
00876     if (formatted.data != NULL) 
00877        PORT_ZFree(formatted.data, modulus_len);
00878     return SECFailure;
00879 }
00880 
00881 /* XXX Doesn't set error code */
00882 SECStatus
00883 RSA_DecryptRaw(NSSLOWKEYPrivateKey *key, 
00884                unsigned char *      output, 
00885               unsigned int *       output_len,
00886                unsigned int         max_output_len, 
00887               unsigned char *      input, 
00888               unsigned int         input_len)
00889 {
00890     SECStatus     rv;
00891     unsigned int  modulus_len = nsslowkey_PrivateModulusLen(key);
00892 
00893     if (modulus_len <= 0) 
00894        goto failure;
00895     if (modulus_len > max_output_len) 
00896        goto failure;
00897     PORT_Assert(key->keyType == NSSLOWKEYRSAKey);
00898     if (key->keyType != NSSLOWKEYRSAKey)
00899        goto failure;
00900     if (input_len != modulus_len) 
00901        goto failure;
00902 
00903     rv = RSA_PrivateKeyOp(&key->u.rsa, output, input);
00904     if (rv != SECSuccess) {
00905        if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
00906            sftk_fatalError = PR_TRUE;
00907        }
00908        goto failure;
00909     }
00910 
00911     *output_len = modulus_len;
00912     return SECSuccess;
00913 
00914 failure:
00915     return SECFailure;
00916 }