Imported Upstream version 3.13.6
[platform/upstream/nss.git] / mozilla / security / nss / cmd / shlibsign / shlibsign.c
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]))
87 CK_BBOOL true = CK_TRUE;
88 CK_BBOOL false = CK_FALSE;
89 static PRBool verbose = PR_FALSE;
90
91 static void
92 usage (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
105 static void 
106 long_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
130 static char * 
131 mkoutput(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
147 static void 
148 lperror(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
156 static void
157 encodeInt(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
166 static PRStatus 
167 writeItem(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
191 static 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
209 static 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
214 static 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
232 static 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
250 static 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
268 static const unsigned int counter=1496;
269
270 struct tuple_str {
271     CK_RV         errNum;
272     const char * errString;
273 };
274
275 typedef struct tuple_str tuple_str;
276
277 static 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
369 static 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  */
374 static const char *
375 CK_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
421 static void 
422 pk11error(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
434 static void 
435 logIt(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
445 static CK_RV 
446 softokn_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
480 cleanup:
481     if (moduleSpec) {
482         PR_smprintf_free(moduleSpec);
483     }
484
485     return crv;
486 }
487
488 static char * 
489 filePasswd(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
519 static void 
520 checkPath(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
541 static CK_SLOT_ID *
542 getSlotList(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
576 int 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
1086 cleanup:
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 }