PageRenderTime 72ms CodeModel.GetById 11ms app.highlight 52ms RepoModel.GetById 1ms app.codeStats 1ms

/security/nss/cmd/shlibsign/shlibsign.c

http://github.com/zpao/v8monkey
C | 1123 lines | 916 code | 107 blank | 100 comment | 159 complexity | ffdb2df87dcf4f448496e8e598f8550d MD5 | raw file
   1/* ***** BEGIN LICENSE BLOCK *****
   2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   3 *
   4 * The contents of this file are subject to the Mozilla Public License Version
   5 * 1.1 (the "License"); you may not use this file except in compliance with
   6 * the License. You may obtain a copy of the License at
   7 * http://www.mozilla.org/MPL/
   8 *
   9 * Software distributed under the License is distributed on an "AS IS" basis,
  10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11 * for the specific language governing rights and limitations under the
  12 * License.
  13 *
  14 * The Original Code is the Netscape security libraries.
  15 *
  16 * The Initial Developer of the Original Code is
  17 * Netscape Communications Corporation.
  18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
  19 * the Initial Developer. All Rights Reserved.
  20 *
  21 * Contributor(s):
  22 *
  23 * Alternatively, the contents of this file may be used under the terms of
  24 * either the GNU General Public License Version 2 or later (the "GPL"), or
  25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26 * in which case the provisions of the GPL or the LGPL are applicable instead
  27 * of those above. If you wish to allow use of your version of this file only
  28 * under the terms of either the GPL or the LGPL, and not to allow others to
  29 * use your version of this file under the terms of the MPL, indicate your
  30 * decision by deleting the provisions above and replace them with the notice
  31 * and other provisions required by the GPL or the LGPL. If you do not delete
  32 * the provisions above, a recipient may use your version of this file under
  33 * the terms of any one of the MPL, the GPL or the LGPL.
  34 *
  35 * ***** END LICENSE BLOCK ***** */
  36
  37/*
  38 * shlibsign creates the checksum (.chk) files for the NSS libraries,
  39 * libsoftokn3/softokn3 and libfreebl/freebl (platforms can have 
  40 * multiple freebl variants), that contain the NSS cryptograhic boundary.
  41 *
  42 * The generated .chk files must be put in the same directory as
  43 * the NSS libraries they were generated for.
  44 *
  45 * When in FIPS 140 mode, the NSS Internal FIPS PKCS #11 Module will
  46 * compute the checksum for the NSS cryptographic boundary libraries
  47 * and compare the checksum with the value in .chk file.
  48 *
  49 * $Id: shlibsign.c,v 1.19 2011/04/08 04:02:53 wtc%google.com Exp $
  50 */
  51
  52#ifdef XP_UNIX
  53#define USES_LINKS 1
  54#endif
  55
  56#include <assert.h>
  57#include <stdio.h>
  58#include <stdlib.h>
  59#include <string.h>
  60#include <stdarg.h>
  61
  62#ifdef USES_LINKS
  63#include <unistd.h>
  64#include <sys/param.h>
  65#include <sys/types.h>
  66#include <sys/stat.h>
  67#endif
  68
  69/* nspr headers */
  70#include "prlink.h"
  71#include "prprf.h"
  72#include "prenv.h"
  73#include "plgetopt.h"
  74#include "prinit.h"
  75#include "prmem.h"
  76#include "plstr.h"
  77#include "prerror.h"
  78
  79/* softoken headers */
  80#include "pkcs11.h"
  81#include "pkcs11t.h"
  82
  83/* freebl headers */
  84#include "shsign.h"
  85
  86#define NUM_ELEM(array) (sizeof(array)/sizeof(array[0]))
  87CK_BBOOL true = CK_TRUE;
  88CK_BBOOL false = CK_FALSE;
  89static PRBool verbose = PR_FALSE;
  90
  91static void
  92usage (const char *program_name)
  93{
  94    PRFileDesc *debug_out = PR_GetSpecialFD(PR_StandardError);
  95    PR_fprintf (debug_out,
  96                "type %s -H for more detail information.\n", program_name);
  97    PR_fprintf (debug_out,
  98                "Usage: %s [-v] [-V] [-o outfile] [-d dbdir] [-f pwfile]\n"
  99                "          [-F] [-p pwd] -[P dbprefix ] "
 100                "-i shared_library_name\n",
 101                program_name);
 102    exit(1);
 103}
 104
 105static void 
 106long_usage(const char *program_name) 
 107{
 108    PRFileDesc *debug_out = PR_GetSpecialFD(PR_StandardError);
 109    PR_fprintf(debug_out, "%s test program usage:\n", program_name);
 110    PR_fprintf(debug_out, "\t-i <infile>  shared_library_name to process\n");
 111    PR_fprintf(debug_out, "\t-o <outfile> checksum outfile\n");
 112    PR_fprintf(debug_out, "\t-d <path>    database path location\n");
 113    PR_fprintf(debug_out, "\t-P <prefix>  database prefix\n");
 114    PR_fprintf(debug_out, "\t-f <file>    password File : echo pw > file \n");
 115    PR_fprintf(debug_out, "\t-F           FIPS mode\n"); 
 116    PR_fprintf(debug_out, "\t-p <pwd>     password\n");
 117    PR_fprintf(debug_out, "\t-v           verbose output\n");
 118    PR_fprintf(debug_out, "\t-V           perform Verify operations\n");
 119    PR_fprintf(debug_out, "\t-?           short help message\n");
 120    PR_fprintf(debug_out, "\t-h           short help message\n");
 121    PR_fprintf(debug_out, "\t-H           this help message\n");
 122    PR_fprintf(debug_out, "\n\n\tNote: Use of FIPS mode requires your ");
 123    PR_fprintf(debug_out, "library path is using \n");
 124    PR_fprintf(debug_out, "\t      pre-existing libraries with generated ");
 125    PR_fprintf(debug_out, "checksum files\n");
 126    PR_fprintf(debug_out, "\t      and database in FIPS mode \n");
 127    exit(1);
 128}
 129
 130static char * 
 131mkoutput(const char *input)
 132{
 133    int in_len = strlen(input);
 134    char *output = PR_Malloc(in_len+sizeof(SGN_SUFFIX));
 135    int index = in_len + 1 - sizeof("."SHLIB_SUFFIX);
 136
 137    if ((index > 0) && 
 138        (PL_strncmp(&input[index],
 139                 "."SHLIB_SUFFIX,sizeof("."SHLIB_SUFFIX)) == 0)) {
 140        in_len = index;
 141    }
 142    memcpy(output,input,in_len);
 143    memcpy(&output[in_len],SGN_SUFFIX,sizeof(SGN_SUFFIX));
 144    return output;
 145}
 146
 147static void 
 148lperror(const char *string) {
 149    PRErrorCode errorcode;
 150
 151    errorcode = PR_GetError();
 152    PR_fprintf(PR_STDERR, "%s: %d: %s\n", string, errorcode,
 153                PR_ErrorToString(errorcode, PR_LANGUAGE_I_DEFAULT));
 154}
 155
 156static void
 157encodeInt(unsigned char *buf, int val)
 158{
 159    buf[3] = (val >> 0) & 0xff;
 160    buf[2] = (val >>  8) & 0xff;
 161    buf[1] = (val >> 16) & 0xff;
 162    buf[0] = (val >> 24) & 0xff;
 163    return;
 164}
 165
 166static PRStatus 
 167writeItem(PRFileDesc *fd, CK_VOID_PTR pValue,
 168          CK_ULONG ulValueLen, char *file)
 169{
 170    unsigned char buf[4];
 171    int bytesWritten;
 172    if (ulValueLen == 0) {
 173        PR_fprintf(PR_STDERR, "call to writeItem with 0 bytes of data.\n");
 174        return PR_FAILURE;
 175    }
 176
 177    encodeInt(buf,ulValueLen);
 178    bytesWritten = PR_Write(fd,buf, 4);
 179    if (bytesWritten != 4) {
 180        lperror(file);
 181        return PR_FAILURE;
 182    }
 183    bytesWritten = PR_Write(fd, pValue, ulValueLen);
 184    if (bytesWritten != ulValueLen) {
 185        lperror(file);
 186        return PR_FAILURE;
 187    }
 188    return PR_SUCCESS;
 189}
 190
 191static const unsigned char prime[] = { 0x00,
 192   0x97, 0x44, 0x1d, 0xcc, 0x0d, 0x39, 0x0d, 0x8d, 
 193   0xcb, 0x75, 0xdc, 0x24, 0x25, 0x6f, 0x01, 0x92, 
 194   0xa1, 0x11, 0x07, 0x6b, 0x70, 0xac, 0x73, 0xd7, 
 195   0x82, 0x28, 0xdf, 0xab, 0x82, 0x0c, 0x41, 0x0c, 
 196   0x95, 0xb3, 0x3c, 0x3d, 0xea, 0x8a, 0xe6, 0x44, 
 197   0x0a, 0xb8, 0xab, 0x90, 0x15, 0x41, 0x11, 0xe8, 
 198   0x48, 0x7b, 0x8d, 0xb0, 0x9c, 0xd3, 0xf2, 0x69, 
 199   0x66, 0xff, 0x66, 0x4b, 0x70, 0x2b, 0xbf, 0xfb, 
 200   0xd6, 0x68, 0x85, 0x76, 0x1e, 0x34, 0xaa, 0xc5, 
 201   0x57, 0x6e, 0x23, 0x02, 0x08, 0x60, 0x6e, 0xfd, 
 202   0x67, 0x76, 0xe1, 0x7c, 0xc8, 0xcb, 0x51, 0x77, 
 203   0xcf, 0xb1, 0x3b, 0x00, 0x2e, 0xfa, 0x21, 0xcd, 
 204   0x34, 0x76, 0x75, 0x01, 0x19, 0xfe, 0xf8, 0x5d, 
 205   0x43, 0xc5, 0x34, 0xf3, 0x7a, 0x95, 0xdc, 0xc2, 
 206   0x58, 0x07, 0x19, 0x2f, 0x1d, 0x6f, 0x9a, 0x77, 
 207   0x7e, 0x55, 0xaa, 0xe7, 0x5a, 0x50, 0x43, 0xd3 };
 208
 209static const unsigned char subprime[] = { 0x0,
 210   0xd8, 0x16, 0x23, 0x34, 0x8a, 0x9e, 0x3a, 0xf5, 
 211   0xd9, 0x10, 0x13, 0x35, 0xaa, 0xf3, 0xf3, 0x54, 
 212   0x0b, 0x31, 0x24, 0xf1 };
 213
 214static const unsigned char base[] = { 
 215    0x03, 0x3a, 0xad, 0xfa, 0x3a, 0x0c, 0xea, 0x0a, 
 216    0x4e, 0x43, 0x32, 0x92, 0xbb, 0x87, 0xf1, 0x11, 
 217    0xc0, 0xad, 0x39, 0x38, 0x56, 0x1a, 0xdb, 0x23, 
 218    0x66, 0xb1, 0x08, 0xda, 0xb6, 0x19, 0x51, 0x42, 
 219    0x93, 0x4f, 0xc3, 0x44, 0x43, 0xa8, 0x05, 0xc1, 
 220    0xf8, 0x71, 0x62, 0x6f, 0x3d, 0xe2, 0xab, 0x6f, 
 221    0xd7, 0x80, 0x22, 0x6f, 0xca, 0x0d, 0xf6, 0x9f, 
 222    0x45, 0x27, 0x83, 0xec, 0x86, 0x0c, 0xda, 0xaa, 
 223    0xd6, 0xe0, 0xd0, 0x84, 0xfd, 0xb1, 0x4f, 0xdc, 
 224    0x08, 0xcd, 0x68, 0x3a, 0x77, 0xc2, 0xc5, 0xf1, 
 225    0x99, 0x0f, 0x15, 0x1b, 0x6a, 0x8c, 0x3d, 0x18, 
 226    0x2b, 0x6f, 0xdc, 0x2b, 0xd8, 0xb5, 0x9b, 0xb8, 
 227    0x2d, 0x57, 0x92, 0x1c, 0x46, 0x27, 0xaf, 0x6d, 
 228    0xe1, 0x45, 0xcf, 0x0b, 0x3f, 0xfa, 0x07, 0xcc, 
 229    0x14, 0x8e, 0xe7, 0xb8, 0xaa, 0xd5, 0xd1, 0x36, 
 230    0x1d, 0x7e, 0x5e, 0x7d, 0xfa, 0x5b, 0x77, 0x1f };
 231
 232static const unsigned char h[] = { 
 233    0x41, 0x87, 0x47, 0x79, 0xd8, 0xba, 0x4e, 0xac, 
 234    0x44, 0x4f, 0x6b, 0xd2, 0x16, 0x5e, 0x04, 0xc6, 
 235    0xc2, 0x29, 0x93, 0x5e, 0xbd, 0xc7, 0xa9, 0x8f, 
 236    0x23, 0xa1, 0xc8, 0xee, 0x80, 0x64, 0xd5, 0x67, 
 237    0x3c, 0xba, 0x59, 0x9a, 0x06, 0x0c, 0xcc, 0x29, 
 238    0x56, 0xc0, 0xb2, 0x21, 0xe0, 0x5b, 0x52, 0xcd, 
 239    0x84, 0x73, 0x57, 0xfd, 0xd8, 0xc3, 0x5b, 0x13, 
 240    0x54, 0xd7, 0x4a, 0x06, 0x86, 0x63, 0x09, 0xa5, 
 241    0xb0, 0x59, 0xe2, 0x32, 0x9e, 0x09, 0xa3, 0x9f, 
 242    0x49, 0x62, 0xcc, 0xa6, 0xf9, 0x54, 0xd5, 0xb2, 
 243    0xc3, 0x08, 0x71, 0x7e, 0xe3, 0x37, 0x50, 0xd6, 
 244    0x7b, 0xa7, 0xc2, 0x60, 0xc1, 0xeb, 0x51, 0x32, 
 245    0xfa, 0xad, 0x35, 0x25, 0x17, 0xf0, 0x7f, 0x23, 
 246    0xe5, 0xa8, 0x01, 0x52, 0xcf, 0x2f, 0xd9, 0xa9, 
 247    0xf6, 0x00, 0x21, 0x15, 0xf1, 0xf7, 0x70, 0xb7, 
 248    0x57, 0x8a, 0xd0, 0x59, 0x6a, 0x82, 0xdc, 0x9c };
 249
 250static const unsigned char seed[] = { 0x00,
 251    0xcc, 0x4c, 0x69, 0x74, 0xf6, 0x72, 0x24, 0x68, 
 252    0x24, 0x4f, 0xd7, 0x50, 0x11, 0x40, 0x81, 0xed, 
 253    0x19, 0x3c, 0x8a, 0x25, 0xbc, 0x78, 0x0a, 0x85, 
 254    0x82, 0x53, 0x70, 0x20, 0xf6, 0x54, 0xa5, 0x1b, 
 255    0xf4, 0x15, 0xcd, 0xff, 0xc4, 0x88, 0xa7, 0x9d, 
 256    0xf3, 0x47, 0x1c, 0x0a, 0xbe, 0x10, 0x29, 0x83, 
 257    0xb9, 0x0f, 0x4c, 0xdf, 0x90, 0x16, 0x83, 0xa2, 
 258    0xb3, 0xe3, 0x2e, 0xc1, 0xc2, 0x24, 0x6a, 0xc4, 
 259    0x9d, 0x57, 0xba, 0xcb, 0x0f, 0x18, 0x75, 0x00, 
 260    0x33, 0x46, 0x82, 0xec, 0xd6, 0x94, 0x77, 0xc3, 
 261    0x4f, 0x4c, 0x58, 0x1c, 0x7f, 0x61, 0x3c, 0x36, 
 262    0xd5, 0x2f, 0xa5, 0x66, 0xd8, 0x2f, 0xce, 0x6e, 
 263    0x8e, 0x20, 0x48, 0x4a, 0xbb, 0xe3, 0xe0, 0xb2, 
 264    0x50, 0x33, 0x63, 0x8a, 0x5b, 0x2d, 0x6a, 0xbe, 
 265    0x4c, 0x28, 0x81, 0x53, 0x5b, 0xe4, 0xf6, 0xfc, 
 266    0x64, 0x06, 0x13, 0x51, 0xeb, 0x4a, 0x91, 0x9c };
 267
 268static const unsigned int counter=1496;
 269
 270struct tuple_str {
 271    CK_RV         errNum;
 272    const char * errString;
 273};
 274
 275typedef struct tuple_str tuple_str;
 276
 277static const tuple_str errStrings[] = {
 278{CKR_OK                              , "CKR_OK                              "},
 279{CKR_CANCEL                          , "CKR_CANCEL                          "},
 280{CKR_HOST_MEMORY                     , "CKR_HOST_MEMORY                     "},
 281{CKR_SLOT_ID_INVALID                 , "CKR_SLOT_ID_INVALID                 "},
 282{CKR_GENERAL_ERROR                   , "CKR_GENERAL_ERROR                   "},
 283{CKR_FUNCTION_FAILED                 , "CKR_FUNCTION_FAILED                 "},
 284{CKR_ARGUMENTS_BAD                   , "CKR_ARGUMENTS_BAD                   "},
 285{CKR_NO_EVENT                        , "CKR_NO_EVENT                        "},
 286{CKR_NEED_TO_CREATE_THREADS          , "CKR_NEED_TO_CREATE_THREADS          "},
 287{CKR_CANT_LOCK                       , "CKR_CANT_LOCK                       "},
 288{CKR_ATTRIBUTE_READ_ONLY             , "CKR_ATTRIBUTE_READ_ONLY             "},
 289{CKR_ATTRIBUTE_SENSITIVE             , "CKR_ATTRIBUTE_SENSITIVE             "},
 290{CKR_ATTRIBUTE_TYPE_INVALID          , "CKR_ATTRIBUTE_TYPE_INVALID          "},
 291{CKR_ATTRIBUTE_VALUE_INVALID         , "CKR_ATTRIBUTE_VALUE_INVALID         "},
 292{CKR_DATA_INVALID                    , "CKR_DATA_INVALID                    "},
 293{CKR_DATA_LEN_RANGE                  , "CKR_DATA_LEN_RANGE                  "},
 294{CKR_DEVICE_ERROR                    , "CKR_DEVICE_ERROR                    "},
 295{CKR_DEVICE_MEMORY                   , "CKR_DEVICE_MEMORY                   "},
 296{CKR_DEVICE_REMOVED                  , "CKR_DEVICE_REMOVED                  "},
 297{CKR_ENCRYPTED_DATA_INVALID          , "CKR_ENCRYPTED_DATA_INVALID          "},
 298{CKR_ENCRYPTED_DATA_LEN_RANGE        , "CKR_ENCRYPTED_DATA_LEN_RANGE        "},
 299{CKR_FUNCTION_CANCELED               , "CKR_FUNCTION_CANCELED               "},
 300{CKR_FUNCTION_NOT_PARALLEL           , "CKR_FUNCTION_NOT_PARALLEL           "},
 301{CKR_FUNCTION_NOT_SUPPORTED          , "CKR_FUNCTION_NOT_SUPPORTED          "},
 302{CKR_KEY_HANDLE_INVALID              , "CKR_KEY_HANDLE_INVALID              "},
 303{CKR_KEY_SIZE_RANGE                  , "CKR_KEY_SIZE_RANGE                  "},
 304{CKR_KEY_TYPE_INCONSISTENT           , "CKR_KEY_TYPE_INCONSISTENT           "},
 305{CKR_KEY_NOT_NEEDED                  , "CKR_KEY_NOT_NEEDED                  "},
 306{CKR_KEY_CHANGED                     , "CKR_KEY_CHANGED                     "},
 307{CKR_KEY_NEEDED                      , "CKR_KEY_NEEDED                      "},
 308{CKR_KEY_INDIGESTIBLE                , "CKR_KEY_INDIGESTIBLE                "},
 309{CKR_KEY_FUNCTION_NOT_PERMITTED      , "CKR_KEY_FUNCTION_NOT_PERMITTED      "},
 310{CKR_KEY_NOT_WRAPPABLE               , "CKR_KEY_NOT_WRAPPABLE               "},
 311{CKR_KEY_UNEXTRACTABLE               , "CKR_KEY_UNEXTRACTABLE               "},
 312{CKR_MECHANISM_INVALID               , "CKR_MECHANISM_INVALID               "},
 313{CKR_MECHANISM_PARAM_INVALID         , "CKR_MECHANISM_PARAM_INVALID         "},
 314{CKR_OBJECT_HANDLE_INVALID           , "CKR_OBJECT_HANDLE_INVALID           "},
 315{CKR_OPERATION_ACTIVE                , "CKR_OPERATION_ACTIVE                "},
 316{CKR_OPERATION_NOT_INITIALIZED       , "CKR_OPERATION_NOT_INITIALIZED       "},
 317{CKR_PIN_INCORRECT                   , "CKR_PIN_INCORRECT                   "},
 318{CKR_PIN_INVALID                     , "CKR_PIN_INVALID                     "},
 319{CKR_PIN_LEN_RANGE                   , "CKR_PIN_LEN_RANGE                   "},
 320{CKR_PIN_EXPIRED                     , "CKR_PIN_EXPIRED                     "},
 321{CKR_PIN_LOCKED                      , "CKR_PIN_LOCKED                      "},
 322{CKR_SESSION_CLOSED                  , "CKR_SESSION_CLOSED                  "},
 323{CKR_SESSION_COUNT                   , "CKR_SESSION_COUNT                   "},
 324{CKR_SESSION_HANDLE_INVALID          , "CKR_SESSION_HANDLE_INVALID          "},
 325{CKR_SESSION_PARALLEL_NOT_SUPPORTED  , "CKR_SESSION_PARALLEL_NOT_SUPPORTED  "},
 326{CKR_SESSION_READ_ONLY               , "CKR_SESSION_READ_ONLY               "},
 327{CKR_SESSION_EXISTS                  , "CKR_SESSION_EXISTS                  "},
 328{CKR_SESSION_READ_ONLY_EXISTS        , "CKR_SESSION_READ_ONLY_EXISTS        "},
 329{CKR_SESSION_READ_WRITE_SO_EXISTS    , "CKR_SESSION_READ_WRITE_SO_EXISTS    "},
 330{CKR_SIGNATURE_INVALID               , "CKR_SIGNATURE_INVALID               "},
 331{CKR_SIGNATURE_LEN_RANGE             , "CKR_SIGNATURE_LEN_RANGE             "},
 332{CKR_TEMPLATE_INCOMPLETE             , "CKR_TEMPLATE_INCOMPLETE             "},
 333{CKR_TEMPLATE_INCONSISTENT           , "CKR_TEMPLATE_INCONSISTENT           "},
 334{CKR_TOKEN_NOT_PRESENT               , "CKR_TOKEN_NOT_PRESENT               "},
 335{CKR_TOKEN_NOT_RECOGNIZED            , "CKR_TOKEN_NOT_RECOGNIZED            "},
 336{CKR_TOKEN_WRITE_PROTECTED           , "CKR_TOKEN_WRITE_PROTECTED           "},
 337{CKR_UNWRAPPING_KEY_HANDLE_INVALID   , "CKR_UNWRAPPING_KEY_HANDLE_INVALID   "},
 338{CKR_UNWRAPPING_KEY_SIZE_RANGE       , "CKR_UNWRAPPING_KEY_SIZE_RANGE       "},
 339{CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT, "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT"},
 340{CKR_USER_ALREADY_LOGGED_IN          , "CKR_USER_ALREADY_LOGGED_IN          "},
 341{CKR_USER_NOT_LOGGED_IN              , "CKR_USER_NOT_LOGGED_IN              "},
 342{CKR_USER_PIN_NOT_INITIALIZED        , "CKR_USER_PIN_NOT_INITIALIZED        "},
 343{CKR_USER_TYPE_INVALID               , "CKR_USER_TYPE_INVALID               "},
 344{CKR_USER_ANOTHER_ALREADY_LOGGED_IN  , "CKR_USER_ANOTHER_ALREADY_LOGGED_IN  "},
 345{CKR_USER_TOO_MANY_TYPES             , "CKR_USER_TOO_MANY_TYPES             "},
 346{CKR_WRAPPED_KEY_INVALID             , "CKR_WRAPPED_KEY_INVALID             "},
 347{CKR_WRAPPED_KEY_LEN_RANGE           , "CKR_WRAPPED_KEY_LEN_RANGE           "},
 348{CKR_WRAPPING_KEY_HANDLE_INVALID     , "CKR_WRAPPING_KEY_HANDLE_INVALID     "},
 349{CKR_WRAPPING_KEY_SIZE_RANGE         , "CKR_WRAPPING_KEY_SIZE_RANGE         "},
 350{CKR_WRAPPING_KEY_TYPE_INCONSISTENT  , "CKR_WRAPPING_KEY_TYPE_INCONSISTENT  "},
 351{CKR_RANDOM_SEED_NOT_SUPPORTED       , "CKR_RANDOM_SEED_NOT_SUPPORTED       "},
 352{CKR_RANDOM_NO_RNG                   , "CKR_RANDOM_NO_RNG                   "},
 353{CKR_DOMAIN_PARAMS_INVALID           , "CKR_DOMAIN_PARAMS_INVALID           "},
 354{CKR_BUFFER_TOO_SMALL                , "CKR_BUFFER_TOO_SMALL                "},
 355{CKR_SAVED_STATE_INVALID             , "CKR_SAVED_STATE_INVALID             "},
 356{CKR_INFORMATION_SENSITIVE           , "CKR_INFORMATION_SENSITIVE           "},
 357{CKR_STATE_UNSAVEABLE                , "CKR_STATE_UNSAVEABLE                "},
 358{CKR_CRYPTOKI_NOT_INITIALIZED        , "CKR_CRYPTOKI_NOT_INITIALIZED        "},
 359{CKR_CRYPTOKI_ALREADY_INITIALIZED    , "CKR_CRYPTOKI_ALREADY_INITIALIZED    "},
 360{CKR_MUTEX_BAD                       , "CKR_MUTEX_BAD                       "},
 361{CKR_MUTEX_NOT_LOCKED                , "CKR_MUTEX_NOT_LOCKED                "},
 362{CKR_FUNCTION_REJECTED               , "CKR_FUNCTION_REJECTED               "},
 363{CKR_VENDOR_DEFINED                  , "CKR_VENDOR_DEFINED                  "},
 364{0xCE534351                          , "CKR_NETSCAPE_CERTDB_FAILED          "},
 365{0xCE534352                          , "CKR_NETSCAPE_KEYDB_FAILED           "}
 366
 367};
 368
 369static const CK_ULONG numStrings = sizeof(errStrings) / sizeof(tuple_str);
 370
 371/* Returns constant error string for "CRV".
 372 * Returns "unknown error" if errNum is unknown.
 373 */
 374static const char *
 375CK_RVtoStr(CK_RV errNum) {
 376    CK_ULONG low  = 1;
 377    CK_ULONG high = numStrings - 1;
 378    CK_ULONG i;
 379    CK_RV num;
 380    static int initDone;
 381
 382    /* make sure table is in  ascending order.
 383     * binary search depends on it.
 384     */
 385    if (!initDone) {
 386        CK_RV lastNum = CKR_OK;
 387        for (i = low; i <= high; ++i) {
 388            num = errStrings[i].errNum;
 389            if (num <= lastNum) {
 390                PR_fprintf(PR_STDERR,
 391                        "sequence error in error strings at item %d\n"
 392                        "error %d (%s)\n"
 393                        "should come after \n"
 394                        "error %d (%s)\n",
 395                        (int) i, (int) lastNum, errStrings[i-1].errString,
 396                        (int) num, errStrings[i].errString);
 397            }
 398            lastNum = num;
 399        }
 400        initDone = 1;
 401    }
 402
 403    /* Do binary search of table. */
 404    while (low + 1 < high) {
 405        i = (low + high) / 2;
 406        num = errStrings[i].errNum;
 407        if (errNum == num)
 408            return errStrings[i].errString;
 409        if (errNum < num)
 410            high = i;
 411        else
 412            low = i;
 413    }
 414    if (errNum == errStrings[low].errNum)
 415        return errStrings[low].errString;
 416    if (errNum == errStrings[high].errNum)
 417        return errStrings[high].errString;
 418    return "unknown error";
 419}
 420
 421static void 
 422pk11error(const char *string, CK_RV crv) {
 423    PRErrorCode errorcode;
 424
 425    PR_fprintf(PR_STDERR, "%s: 0x%08lX, %-26s\n", string, crv, CK_RVtoStr(crv));
 426
 427    errorcode = PR_GetError();
 428    if (errorcode) {
 429        PR_fprintf(PR_STDERR, "NSPR error code: %d: %s\n", errorcode,
 430                PR_ErrorToString(errorcode, PR_LANGUAGE_I_DEFAULT));
 431    }
 432}
 433
 434static void 
 435logIt(const char *fmt, ...) {
 436    va_list args;
 437
 438    if (verbose) {
 439        va_start (args, fmt);
 440        vprintf(fmt, args);
 441        va_end(args);
 442    }
 443}
 444
 445static CK_RV 
 446softokn_Init(CK_FUNCTION_LIST_PTR pFunctionList, const char * configDir,
 447            const char * dbPrefix) {
 448
 449    CK_RV crv = CKR_OK;
 450    CK_C_INITIALIZE_ARGS initArgs;
 451    char *moduleSpec = NULL;
 452
 453    initArgs.CreateMutex = NULL;
 454    initArgs.DestroyMutex = NULL;
 455    initArgs.LockMutex = NULL;
 456    initArgs.UnlockMutex = NULL;
 457    initArgs.flags = CKF_OS_LOCKING_OK;
 458    if (configDir) {
 459        moduleSpec = PR_smprintf("configdir='%s' certPrefix='%s' "
 460                             "keyPrefix='%s' secmod='secmod.db' flags=ReadOnly ",
 461                             configDir, dbPrefix, dbPrefix);
 462    } else {
 463        moduleSpec = PR_smprintf("configdir='' certPrefix='' keyPrefix='' "
 464                                 "secmod='' flags=noCertDB, noModDB");
 465    }
 466    if (!moduleSpec) {
 467        PR_fprintf(PR_STDERR, "softokn_Init: out of memory error\n");
 468        return CKR_HOST_MEMORY;
 469    } 
 470    logIt("moduleSpec %s\n", moduleSpec);
 471    initArgs.LibraryParameters = (CK_CHAR_PTR *) moduleSpec;
 472    initArgs.pReserved = NULL;
 473
 474    crv = pFunctionList->C_Initialize(&initArgs);
 475    if (crv != CKR_OK) {
 476        pk11error("C_Initialize failed", crv);
 477        goto cleanup;
 478    }
 479
 480cleanup:
 481    if (moduleSpec) {
 482        PR_smprintf_free(moduleSpec);
 483    }
 484
 485    return crv;
 486}
 487
 488static char * 
 489filePasswd(char *pwFile)
 490{
 491    unsigned char phrase[200];
 492    PRFileDesc *fd;
 493    PRInt32 nb;
 494    int i;
 495
 496    if (!pwFile)
 497        return 0;
 498
 499    fd = PR_Open(pwFile, PR_RDONLY, 0);
 500    if (!fd) {
 501        lperror(pwFile);
 502        return NULL;
 503    }
 504
 505    nb = PR_Read(fd, phrase, sizeof(phrase));
 506
 507    PR_Close(fd);
 508    /* handle the Windows EOL case */
 509    i = 0;
 510    while (phrase[i] != '\r' && phrase[i] != '\n' && i < nb) i++;
 511    phrase[i] = '\0';
 512    if (nb == 0) {
 513        PR_fprintf(PR_STDERR,"password file contains no data\n");
 514        return NULL;
 515    }
 516    return (char*) PL_strdup((char*)phrase);
 517}
 518
 519static void 
 520checkPath(char *string)
 521{
 522    char *src;
 523    char *dest;
 524
 525    /*
 526     * windows support convert any back slashes to
 527     * forward slashes.
 528     */
 529    for (src=string, dest=string; *src; src++,dest++) {
 530        if (*src == '\\') {
 531            *dest = '/';
 532        }
 533    }
 534    dest--;
 535    /* if the last char is a / set it to 0 */
 536    if (*dest == '/')
 537        *dest = 0;
 538
 539}
 540
 541static CK_SLOT_ID *
 542getSlotList(CK_FUNCTION_LIST_PTR pFunctionList,
 543            CK_ULONG slotIndex) {
 544    CK_RV crv = CKR_OK;
 545    CK_SLOT_ID *pSlotList = NULL;
 546    CK_ULONG slotCount;
 547
 548    /* Get slot list */
 549    crv = pFunctionList->C_GetSlotList(CK_FALSE /* all slots */,
 550                                       NULL, &slotCount);
 551    if (crv != CKR_OK) {
 552        pk11error( "C_GetSlotList failed", crv);
 553        return NULL;
 554    }
 555
 556    if (slotIndex >= slotCount) {
 557        PR_fprintf(PR_STDERR, "provided slotIndex is greater than the slot count.");
 558        return NULL;
 559    }
 560
 561    pSlotList = (CK_SLOT_ID *)PR_Malloc(slotCount * sizeof(CK_SLOT_ID));
 562    if (!pSlotList) {
 563        lperror("failed to allocate slot list");
 564        return NULL;
 565    }
 566    crv = pFunctionList->C_GetSlotList(CK_FALSE /* all slots */,
 567                                       pSlotList, &slotCount);
 568    if (crv != CKR_OK) {
 569        pk11error( "C_GetSlotList failed", crv);
 570        if (pSlotList) PR_Free(pSlotList);
 571        return NULL;
 572    }
 573    return pSlotList;
 574}
 575
 576int main(int argc, char **argv)
 577{
 578    PLOptState *optstate;
 579    char *program_name;
 580    char *libname = NULL;
 581    PRLibrary *lib;
 582    PRFileDesc *fd;
 583    PRStatus rv = PR_SUCCESS;
 584    const char  *input_file = NULL; /* read/create encrypted data from here */
 585    char  *output_file = NULL;	/* write new encrypted data here */
 586    int bytesRead;
 587    int bytesWritten;
 588    unsigned char file_buf[512];
 589    int count=0;
 590    int i;
 591    PRBool verify = PR_FALSE;
 592    static PRBool FIPSMODE = PR_FALSE;
 593
 594#ifdef USES_LINKS
 595    int ret;
 596    struct stat stat_buf;
 597    char link_buf[MAXPATHLEN+1];
 598    char *link_file = NULL;
 599#endif
 600
 601    char *pwd = NULL;
 602    char *configDir = NULL;
 603    char *dbPrefix = NULL;
 604    char *disableUnload = NULL;
 605
 606    CK_C_GetFunctionList pC_GetFunctionList;
 607    CK_TOKEN_INFO tokenInfo;
 608    CK_FUNCTION_LIST_PTR pFunctionList = NULL;
 609    CK_RV crv = CKR_OK;
 610    CK_SESSION_HANDLE hRwSession;
 611    CK_SLOT_ID *pSlotList = NULL;
 612    CK_ULONG slotIndex = 0; 
 613    CK_MECHANISM digestmech;
 614    CK_ULONG digestLen = 0;
 615    CK_BYTE digest[20]; /* SHA1_LENGTH */
 616    CK_BYTE sign[40];   /* DSA SIGNATURE LENGTH */
 617    CK_ULONG signLen = 0 ;
 618    CK_MECHANISM signMech = {
 619        CKM_DSA, NULL, 0
 620    };
 621
 622    /*** DSA Key ***/
 623
 624    CK_MECHANISM dsaKeyPairGenMech;
 625    CK_ATTRIBUTE dsaPubKeyTemplate[5];
 626    CK_ATTRIBUTE dsaPrivKeyTemplate[5];
 627    CK_OBJECT_HANDLE hDSApubKey = CK_INVALID_HANDLE;
 628    CK_OBJECT_HANDLE hDSAprivKey = CK_INVALID_HANDLE;
 629
 630    CK_BYTE dsaPubKey[128];
 631    CK_ATTRIBUTE dsaPubKeyValue;
 632
 633    /* DSA key init */
 634    dsaPubKeyTemplate[0].type       = CKA_PRIME;
 635    dsaPubKeyTemplate[0].pValue     = (CK_VOID_PTR) &prime;
 636    dsaPubKeyTemplate[0].ulValueLen = sizeof(prime);
 637    dsaPubKeyTemplate[1].type = CKA_SUBPRIME;
 638    dsaPubKeyTemplate[1].pValue = (CK_VOID_PTR) &subprime;
 639    dsaPubKeyTemplate[1].ulValueLen = sizeof(subprime);
 640    dsaPubKeyTemplate[2].type = CKA_BASE;
 641    dsaPubKeyTemplate[2].pValue = (CK_VOID_PTR) &base;
 642    dsaPubKeyTemplate[2].ulValueLen = sizeof(base);
 643    dsaPubKeyTemplate[3].type = CKA_TOKEN;
 644    dsaPubKeyTemplate[3].pValue = &false; /* session object */
 645    dsaPubKeyTemplate[3].ulValueLen = sizeof(false);
 646    dsaPubKeyTemplate[4].type = CKA_VERIFY;
 647    dsaPubKeyTemplate[4].pValue = &true;
 648    dsaPubKeyTemplate[4].ulValueLen = sizeof(true);
 649    dsaKeyPairGenMech.mechanism      = CKM_DSA_KEY_PAIR_GEN;
 650    dsaKeyPairGenMech.pParameter = NULL;
 651    dsaKeyPairGenMech.ulParameterLen = 0;
 652    dsaPrivKeyTemplate[0].type       = CKA_TOKEN;
 653    dsaPrivKeyTemplate[0].pValue     = &false; /* session object */
 654    dsaPrivKeyTemplate[0].ulValueLen = sizeof(false);
 655    dsaPrivKeyTemplate[1].type       = CKA_PRIVATE;
 656    dsaPrivKeyTemplate[1].pValue     = &true;
 657    dsaPrivKeyTemplate[1].ulValueLen = sizeof(true);
 658    dsaPrivKeyTemplate[2].type       = CKA_SENSITIVE;
 659    dsaPrivKeyTemplate[2].pValue     = &true; 
 660    dsaPrivKeyTemplate[2].ulValueLen = sizeof(true);
 661    dsaPrivKeyTemplate[3].type       = CKA_SIGN,
 662    dsaPrivKeyTemplate[3].pValue     = &true;
 663    dsaPrivKeyTemplate[3].ulValueLen = sizeof(true);
 664    dsaPrivKeyTemplate[4].type       = CKA_EXTRACTABLE;
 665    dsaPrivKeyTemplate[4].pValue     = &false;
 666    dsaPrivKeyTemplate[4].ulValueLen = sizeof(false);
 667    digestmech.mechanism = CKM_SHA_1;
 668    digestmech.pParameter = NULL;
 669    digestmech.ulParameterLen = 0;
 670
 671    program_name = strrchr(argv[0], '/');
 672    program_name = program_name ? (program_name + 1) : argv[0];
 673    optstate = PL_CreateOptState (argc, argv, "i:o:f:Fd:hH?p:P:vVs:");
 674    if (optstate == NULL) {
 675        lperror("PL_CreateOptState failed");
 676        return 1;
 677    }
 678
 679    while (PL_GetNextOpt (optstate) == PL_OPT_OK) {
 680        switch (optstate->option) {
 681
 682            case 'd':
 683                if (!optstate->value) {
 684                    PL_DestroyOptState(optstate);
 685                    usage(program_name);
 686                }
 687                configDir = PL_strdup(optstate->value);
 688                checkPath(configDir);
 689                break;
 690
 691                case 'i':
 692                if (!optstate->value) {
 693                    PL_DestroyOptState(optstate);
 694                    usage(program_name);
 695                }
 696                input_file = optstate->value;
 697                break;
 698
 699                case 'o':
 700                if (!optstate->value) {
 701                    PL_DestroyOptState(optstate);
 702                    usage(program_name);
 703                }
 704                output_file = PL_strdup(optstate->value);
 705                break;
 706
 707                case 'f':
 708                if (!optstate->value) {
 709                    PL_DestroyOptState(optstate);
 710                    usage(program_name);
 711                }
 712                pwd = filePasswd((char *)optstate->value);
 713                if (!pwd) usage(program_name);
 714                break;
 715
 716                case 'F':
 717                FIPSMODE = PR_TRUE;
 718                break;
 719
 720                case 'p':
 721                if (!optstate->value) {
 722                    PL_DestroyOptState(optstate);
 723                    usage(program_name);
 724                }
 725                pwd =  PL_strdup(optstate->value);
 726                break;
 727
 728                case 'P':
 729                if (!optstate->value) {
 730                    PL_DestroyOptState(optstate);
 731                    usage(program_name);
 732                }
 733                dbPrefix = PL_strdup(optstate->value);
 734                break;
 735
 736                case 'v':
 737                verbose = PR_TRUE;
 738                break;
 739
 740                case 'V':
 741                verify = PR_TRUE;
 742                break;
 743
 744                case 'H':
 745                PL_DestroyOptState(optstate);
 746                long_usage (program_name);
 747                return 1;
 748                break;
 749
 750                case 'h':
 751                case '?':
 752                default:
 753                PL_DestroyOptState(optstate);
 754                usage(program_name);
 755                return 1;
 756                break;
 757        }
 758    }
 759    PL_DestroyOptState(optstate);
 760
 761    if (!input_file) {
 762        usage(program_name);
 763        return 1;
 764    }
 765
 766    /* Get the platform-dependent library name of the
 767     * NSS cryptographic module.
 768     */
 769    libname = PR_GetLibraryName(NULL, "softokn3");
 770    assert(libname != NULL);
 771    lib = PR_LoadLibrary(libname);
 772    assert(lib != NULL);
 773    PR_FreeLibraryName(libname);
 774
 775
 776    if (FIPSMODE) {
 777        /* FIPSMODE == FC_GetFunctionList */
 778        /* library path must be set to an already signed softokn3/freebl */
 779        pC_GetFunctionList = (CK_C_GetFunctionList)
 780                             PR_FindFunctionSymbol(lib, "FC_GetFunctionList");
 781    } else {
 782        /* NON FIPS mode  == C_GetFunctionList */
 783        pC_GetFunctionList = (CK_C_GetFunctionList)
 784                             PR_FindFunctionSymbol(lib, "C_GetFunctionList");
 785     }
 786    assert(pC_GetFunctionList != NULL);
 787
 788    crv = (*pC_GetFunctionList)(&pFunctionList);
 789    assert(crv == CKR_OK);
 790
 791    if (configDir) {
 792    if (!dbPrefix) {
 793            dbPrefix = PL_strdup("");
 794        }
 795        crv = softokn_Init(pFunctionList, configDir, dbPrefix);
 796        if (crv != CKR_OK) {
 797            logIt("Failed to use provided database directory "
 798                  "will just initialize the volatile certdb.\n");
 799            crv = softokn_Init(pFunctionList, NULL, NULL); /* NoDB Init */
 800        }
 801    } else {
 802        crv = softokn_Init(pFunctionList, NULL, NULL); /* NoDB Init */
 803    }
 804
 805    if (crv != CKR_OK) {
 806        pk11error( "Initiailzing softoken failed", crv);
 807        goto cleanup;
 808    }
 809
 810    pSlotList = getSlotList(pFunctionList, slotIndex);
 811    if (pSlotList == NULL) {
 812        PR_fprintf(PR_STDERR, "getSlotList failed");
 813        goto cleanup;
 814    }
 815
 816    crv = pFunctionList->C_OpenSession(pSlotList[slotIndex],
 817                                       CKF_RW_SESSION | CKF_SERIAL_SESSION,
 818                                       NULL, NULL, &hRwSession);
 819    if (crv != CKR_OK) {
 820        pk11error( "Opening a read/write session failed", crv);
 821        goto cleanup;
 822    }
 823
 824    /* check if a password is needed */
 825    crv = pFunctionList->C_GetTokenInfo(pSlotList[slotIndex], &tokenInfo);
 826    if (crv != CKR_OK) {
 827        pk11error( "C_GetTokenInfo failed", crv);
 828        goto cleanup;
 829    }
 830    if (tokenInfo.flags & CKF_LOGIN_REQUIRED) {
 831        if (pwd) {
 832            int pwdLen = strlen((const char*)pwd); 
 833            crv = pFunctionList->C_Login(hRwSession, CKU_USER, 
 834                                (CK_UTF8CHAR_PTR) pwd, (CK_ULONG)pwdLen);
 835            if (crv != CKR_OK) {
 836                pk11error("C_Login failed", crv);
 837                goto cleanup;
 838            }
 839        } else {
 840            PR_fprintf(PR_STDERR, "Please provide the password for the token");
 841            goto cleanup;
 842        }
 843    } else if (pwd) {
 844        logIt("A password was provided but the password was not used.\n");
 845    }
 846
 847    /* Generate a DSA key pair */
 848    logIt("Generate a DSA key pair ... \n");
 849    crv = pFunctionList->C_GenerateKeyPair(hRwSession, &dsaKeyPairGenMech,
 850                                           dsaPubKeyTemplate,
 851                                           NUM_ELEM(dsaPubKeyTemplate),
 852                                           dsaPrivKeyTemplate,
 853                                           NUM_ELEM(dsaPrivKeyTemplate),
 854                                           &hDSApubKey, &hDSAprivKey);
 855    if (crv != CKR_OK) {
 856        pk11error("DSA key pair generation failed", crv);
 857        goto cleanup;
 858    }
 859
 860    /* open the shared library */
 861    fd = PR_OpenFile(input_file,PR_RDONLY,0);
 862    if (fd == NULL ) {
 863        lperror(input_file);
 864        goto cleanup;
 865    }
 866#ifdef USES_LINKS
 867    ret = lstat(input_file, &stat_buf);
 868    if (ret < 0) {
 869        perror(input_file);
 870        goto cleanup;
 871    }
 872    if (S_ISLNK(stat_buf.st_mode)) {
 873        char *dirpath,*dirend;
 874        ret = readlink(input_file, link_buf, sizeof(link_buf) - 1);
 875        if (ret < 0) {
 876            perror(input_file);
 877            goto cleanup;
 878        }
 879        link_buf[ret] = 0;
 880        link_file = mkoutput(input_file);
 881        /* get the dirname of input_file */
 882        dirpath = PL_strdup(input_file);
 883        dirend = strrchr(dirpath, '/');
 884        if (dirend) {
 885            *dirend = '\0';
 886            ret = chdir(dirpath);
 887            if (ret < 0) {
 888                perror(dirpath);
 889                goto cleanup;
 890            }
 891        }
 892        PL_strfree(dirpath);
 893        input_file = link_buf;
 894        /* get the basename of link_file */
 895        dirend = strrchr(link_file, '/');
 896        if (dirend) {
 897            char * tmp_file = NULL;
 898            tmp_file = PL_strdup(dirend +1 );
 899            PL_strfree(link_file);
 900            link_file = tmp_file;
 901        }
 902    }
 903#endif
 904    if (output_file == NULL) {
 905        output_file = mkoutput(input_file);
 906    }
 907
 908    /* compute the digest */
 909    memset(digest, 0, sizeof(digest));
 910    crv = pFunctionList->C_DigestInit(hRwSession, &digestmech);
 911    if (crv != CKR_OK) {
 912        pk11error("C_DigestInit failed", crv);
 913        goto cleanup;
 914    }
 915
 916    /* Digest the file */
 917    while ((bytesRead = PR_Read(fd,file_buf,sizeof(file_buf))) > 0) {
 918        crv = pFunctionList->C_DigestUpdate(hRwSession, (CK_BYTE_PTR)file_buf,
 919                                            bytesRead);
 920        if (crv != CKR_OK) {
 921            pk11error("C_DigestUpdate failed", crv);
 922            goto cleanup;
 923        }
 924        count += bytesRead;
 925    }
 926
 927    /* close the input_File */
 928    PR_Close(fd);
 929    fd = NULL;
 930    if (bytesRead < 0) {
 931        lperror("0 bytes read from input file");
 932        goto cleanup;
 933    }
 934
 935    digestLen = sizeof(digest);
 936    crv = pFunctionList->C_DigestFinal(hRwSession, (CK_BYTE_PTR)digest,
 937                                       &digestLen);
 938    if (crv != CKR_OK) {
 939        pk11error("C_DigestFinal failed", crv);
 940        goto cleanup;
 941    }
 942
 943    if (digestLen != sizeof(digest)) {
 944        PR_fprintf(PR_STDERR, "digestLen has incorrect length %lu "
 945                "it should be %lu \n",digestLen, sizeof(digest));
 946        goto cleanup;
 947    }
 948
 949    /* sign the hash */
 950    memset(sign, 0, sizeof(sign));
 951    /* SignUpdate  */
 952    crv = pFunctionList->C_SignInit(hRwSession, &signMech, hDSAprivKey);
 953    if (crv != CKR_OK) {
 954        pk11error("C_SignInit failed", crv);
 955        goto cleanup;
 956    }
 957
 958    signLen = sizeof(sign);
 959    crv = pFunctionList->C_Sign(hRwSession, (CK_BYTE * ) digest, digestLen,
 960                                sign, &signLen);
 961    if (crv != CKR_OK) {
 962        pk11error("C_Sign failed", crv);
 963        goto cleanup;
 964    }
 965
 966    if (signLen != sizeof(sign)) {
 967        PR_fprintf(PR_STDERR, "signLen has incorrect length %lu "
 968                    "it should be %lu \n", signLen, sizeof(sign));
 969        goto cleanup;
 970    }
 971
 972    if (verify) {
 973        crv = pFunctionList->C_VerifyInit(hRwSession, &signMech, hDSApubKey);
 974        if (crv != CKR_OK) {
 975            pk11error("C_VerifyInit failed", crv);
 976            goto cleanup;
 977        }
 978        crv = pFunctionList->C_Verify(hRwSession, digest, digestLen,
 979                                      sign, signLen);
 980        if (crv != CKR_OK) {
 981            pk11error("C_Verify failed", crv);
 982            goto cleanup;
 983        }
 984    }
 985
 986    if (verbose) {
 987        int j;
 988        PR_fprintf(PR_STDERR,"Library File: %s %d bytes\n",input_file, count);
 989        PR_fprintf(PR_STDERR,"Check File: %s\n",output_file);
 990#ifdef USES_LINKS
 991        if (link_file) {
 992            PR_fprintf(PR_STDERR,"Link: %s\n",link_file);
 993        }
 994#endif
 995        PR_fprintf(PR_STDERR,"  hash: %lu bytes\n", digestLen);
 996#define STEP 10
 997        for (i=0; i < (int) digestLen; i += STEP) {
 998            PR_fprintf(PR_STDERR,"   ");
 999            for (j=0; j < STEP && (i+j) < (int) digestLen; j++) {
1000                PR_fprintf(PR_STDERR," %02x", digest[i+j]);
1001            }
1002            PR_fprintf(PR_STDERR,"\n");
1003        }
1004        PR_fprintf(PR_STDERR,"  signature: %lu bytes\n", signLen);
1005        for (i=0; i < (int) signLen; i += STEP) {
1006            PR_fprintf(PR_STDERR,"   ");
1007            for (j=0; j < STEP && (i+j) < (int) signLen; j++) {
1008                PR_fprintf(PR_STDERR," %02x", sign[i+j]);
1009            }
1010            PR_fprintf(PR_STDERR,"\n");
1011        }
1012    }
1013
1014    /* open the target signature file */
1015    fd = PR_Open(output_file,PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE,0666);
1016    if (fd == NULL ) {
1017        lperror(output_file);
1018        goto cleanup;
1019    }
1020
1021    /*
1022     * we write the key out in a straight binary format because very
1023     * low level libraries need to read an parse this file. Ideally we should
1024     * just derEncode the public key (which would be pretty simple, and be
1025     * more general), but then we'd need to link the ASN.1 decoder with the
1026     * freebl libraries.
1027     */
1028
1029    file_buf[0] = NSS_SIGN_CHK_MAGIC1;
1030    file_buf[1] = NSS_SIGN_CHK_MAGIC2;
1031    file_buf[2] = NSS_SIGN_CHK_MAJOR_VERSION;
1032    file_buf[3] = NSS_SIGN_CHK_MINOR_VERSION;
1033    encodeInt(&file_buf[4],12);  /* offset to data start */
1034    encodeInt(&file_buf[8],CKK_DSA);
1035    bytesWritten = PR_Write(fd,file_buf, 12);
1036    if (bytesWritten != 12) {
1037        lperror(output_file);
1038        goto cleanup;
1039    }
1040
1041    /* get DSA Public KeyValue */
1042    memset(dsaPubKey, 0, sizeof(dsaPubKey));
1043    dsaPubKeyValue.type =CKA_VALUE;
1044    dsaPubKeyValue.pValue = (CK_VOID_PTR) &dsaPubKey;
1045    dsaPubKeyValue.ulValueLen = sizeof(dsaPubKey);
1046
1047    crv = pFunctionList->C_GetAttributeValue(hRwSession, hDSApubKey,
1048                                             &dsaPubKeyValue, 1);
1049    if (crv != CKR_OK && crv != CKR_ATTRIBUTE_TYPE_INVALID) {
1050        pk11error("C_GetAttributeValue failed", crv);
1051        goto cleanup;
1052    }
1053
1054    /* CKA_PRIME */
1055    rv = writeItem(fd,dsaPubKeyTemplate[0].pValue,
1056                   dsaPubKeyTemplate[0].ulValueLen, output_file);
1057    if (rv != PR_SUCCESS) goto cleanup;
1058    /* CKA_SUBPRIME */
1059    rv = writeItem(fd,dsaPubKeyTemplate[1].pValue,
1060                   dsaPubKeyTemplate[1].ulValueLen, output_file);
1061    if (rv != PR_SUCCESS) goto cleanup;
1062    /* CKA_BASE */ 
1063    rv = writeItem(fd,dsaPubKeyTemplate[2].pValue,
1064                   dsaPubKeyTemplate[2].ulValueLen, output_file);
1065    if (rv != PR_SUCCESS) goto cleanup;
1066    /* DSA Public Key value */
1067    rv = writeItem(fd,dsaPubKeyValue.pValue,
1068                   dsaPubKeyValue.ulValueLen, output_file);
1069    if (rv != PR_SUCCESS) goto cleanup;
1070    /* DSA SIGNATURE */
1071    rv = writeItem(fd,&sign, signLen, output_file);
1072    if (rv != PR_SUCCESS) goto cleanup;
1073    PR_Close(fd);
1074
1075#ifdef USES_LINKS
1076    if (link_file) {
1077        (void)unlink(link_file);
1078        ret = symlink(output_file, link_file);
1079        if (ret < 0) {
1080            perror(link_file);
1081            goto cleanup;
1082        }
1083    }
1084#endif
1085
1086cleanup:
1087    if (pFunctionList) {
1088        /* C_Finalize will automatically logout, close session, */
1089        /* and delete the temp objects on the token */
1090        crv = pFunctionList->C_Finalize(NULL);
1091        if (crv != CKR_OK) {
1092            pk11error("C_Finalize failed", crv);
1093        }
1094    }
1095    if (pSlotList) {
1096        PR_Free(pSlotList);
1097    }
1098    if (pwd) {
1099        PL_strfree(pwd);
1100    }
1101    if (configDir) {
1102        PL_strfree(configDir);
1103    }
1104    if (dbPrefix) {
1105        PL_strfree(dbPrefix);
1106    }
1107    if (output_file) { /* allocated by mkoutput function */
1108        PL_strfree(output_file); 
1109    }
1110#ifdef USES_LINKS
1111    if (link_file) { /* allocated by mkoutput function */
1112        PL_strfree(link_file); 
1113    }
1114#endif
1115
1116    disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
1117    if (!disableUnload) {
1118        PR_UnloadLibrary(lib);
1119    }
1120    PR_Cleanup();
1121
1122    return crv;
1123}