Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / cmd / shlibsign / shlibsign.c
blob4d6a73b2ead8f037ac4c778aeccd55612a0f82cc
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
14 * The Original Code is the Netscape security libraries.
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.
21 * Contributor(s):
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.
35 * ***** END LICENSE BLOCK ***** */
38 * Test program for SDR (Secret Decoder Ring) functions.
40 * $Id: shlibsign.c,v 1.14 2005/11/15 00:34:39 julien.pierre.bugs%sun.com Exp $
43 #ifdef XP_UNIX
44 #define USES_LINKS 1
45 #endif
47 #include "nspr.h"
48 #include <stdio.h>
49 #include "nss.h"
50 #include "secutil.h"
51 #include "cert.h"
52 #include "pk11func.h"
54 #include "plgetopt.h"
55 #include "pk11sdr.h"
56 #include "shsign.h"
57 #include "pk11pqg.h"
59 #ifdef USES_LINKS
60 #include <unistd.h>
61 #include <sys/param.h>
62 #include <sys/types.h>
63 #include <sys/stat.h>
64 #endif
66 static void
67 usage (char *program_name)
69 PRFileDesc *pr_stderr;
71 pr_stderr = PR_STDERR;
72 PR_fprintf (pr_stderr, "Usage:");
73 PR_fprintf (pr_stderr, "%s [-v] -i shared_library_name\n", program_name);
76 static char *
77 mkoutput(const char *input)
79 int in_len = PORT_Strlen(input);
80 char *output = PORT_Alloc(in_len+sizeof(SGN_SUFFIX));
81 int index = in_len + 1 - sizeof("."SHLIB_SUFFIX);
83 if ((index > 0) &&
84 (PORT_Strncmp(&input[index],
85 "."SHLIB_SUFFIX,sizeof("."SHLIB_SUFFIX)) == 0)) {
86 in_len = index;
88 PORT_Memcpy(output,input,in_len);
89 PORT_Memcpy(&output[in_len],SGN_SUFFIX,sizeof(SGN_SUFFIX));
90 return output;
94 static void
95 lperror(const char *string)
97 int errNum = PORT_GetError();
98 const char *error = SECU_Strerror(errNum);
99 fprintf(stderr,"%s: %s\n",string, error);
102 static void
103 encodeInt(unsigned char *buf, int val)
105 buf[3] = (val >> 0) & 0xff;
106 buf[2] = (val >> 8) & 0xff;
107 buf[1] = (val >> 16) & 0xff;
108 buf[0] = (val >> 24) & 0xff;
109 return;
112 static SECStatus
113 writeItem(PRFileDesc *fd, SECItem *item, char *file)
115 unsigned char buf[4];
116 int bytesWritten;
118 encodeInt(buf,item->len);
119 bytesWritten = PR_Write(fd,buf, 4);
120 if (bytesWritten != 4) {
121 lperror(file);
122 return SECFailure;
124 bytesWritten = PR_Write(fd, item->data, item->len);
125 if (bytesWritten != item->len) {
126 lperror(file);
127 return SECFailure;
129 return SECSuccess;
134 main (int argc, char **argv)
136 int retval = 1; /* 0 - test succeeded. 1 - test failed */
137 SECStatus rv;
138 PLOptState *optstate;
139 char *program_name;
140 const char *input_file = NULL; /* read encrypted data from here (or create) */
141 char *output_file = NULL; /* write new encrypted data here */
142 PRBool verbose = PR_FALSE;
143 SECKEYPrivateKey *privk = NULL;
144 SECKEYPublicKey *pubk = NULL;
145 PK11SlotInfo *slot = NULL;
146 PRFileDesc *fd;
147 int bytesRead;
148 int bytesWritten;
149 unsigned char file_buf[512];
150 unsigned char hash_buf[SHA1_LENGTH];
151 unsigned char sign_buf[40]; /* DSA_LENGTH */
152 SECItem hash,sign;
153 PK11Context *hashcx = NULL;
154 int ks, count=0;
155 int keySize = 1024;
156 PQGParams *pqgParams = NULL;
157 PQGVerify *pqgVerify = NULL;
158 char* nssDir = NULL;
159 #ifdef USES_LINKS
160 int ret;
161 struct stat stat_buf;
162 char link_buf[MAXPATHLEN+1];
163 char *link_file = NULL;
164 #endif
166 hash.len = sizeof(hash_buf); hash.data = hash_buf;
167 sign.len = sizeof(sign_buf); sign.data = sign_buf;
169 program_name = PL_strrchr(argv[0], '/');
170 program_name = program_name ? (program_name + 1) : argv[0];
172 optstate = PL_CreateOptState (argc, argv, "d:i:o:v");
173 if (optstate == NULL) {
174 SECU_PrintError (program_name, "PL_CreateOptState failed");
175 return 1;
178 while (PL_GetNextOpt (optstate) == PL_OPT_OK) {
179 switch (optstate->option) {
180 #ifdef notdef
181 case '?':
182 short_usage (program_name);
183 return 0;
185 case 'H':
186 long_usage (program_name);
187 return 0;
188 #endif
190 case 'd':
191 nssDir = optstate->value;
192 break;
194 case 'i':
195 input_file = optstate->value;
196 break;
198 case 'o':
199 output_file = PORT_Strdup(optstate->value);
200 break;
202 case 'v':
203 verbose = PR_TRUE;
204 break;
208 if (input_file == NULL) {
209 usage(program_name);
210 return 1;
214 * Initialize the Security libraries.
216 PK11_SetPasswordFunc(SECU_GetModulePassword);
218 if (nssDir) {
219 rv = NSS_Init(nssDir);
220 if (rv != SECSuccess) {
221 rv = NSS_NoDB_Init("");
223 } else {
224 rv = NSS_NoDB_Init("");
227 if (rv != SECSuccess) {
228 lperror("NSS_Init failed");
229 goto prdone;
232 /* Generate a DSA Key pair */
233 slot = PK11_GetBestSlot(CKM_DSA,NULL);
234 if (slot == NULL) {
235 lperror("CKM_DSA");
236 goto loser;
239 printf("Generating DSA Key Pair...."); fflush(stdout);
240 ks = PQG_PBITS_TO_INDEX(keySize);
241 rv = PK11_PQG_ParamGen(ks,&pqgParams, &pqgVerify);
242 if (rv != SECSuccess) {
243 lperror("Generating PQG Params");
244 goto loser;
246 privk = PK11_GenerateKeyPair(slot, CKM_DSA_KEY_PAIR_GEN, pqgParams, &pubk,
247 PR_FALSE, PR_TRUE, NULL);
248 if (privk == NULL) {
249 lperror("Generating DSA Key");
250 goto loser;
253 printf("done\n");
255 /* open the shared library */
256 fd = PR_OpenFile(input_file,PR_RDONLY,0);
257 if (fd == NULL ) {
258 lperror(input_file);
259 goto loser;
261 #ifdef USES_LINKS
262 ret = lstat(input_file, &stat_buf);
263 if (ret < 0) {
264 perror(input_file);
265 goto loser;
267 if (S_ISLNK(stat_buf.st_mode)) {
268 char *dirpath,*dirend;
269 ret = readlink(input_file, link_buf, sizeof(link_buf) - 1);
270 if (ret < 0) {
271 perror(input_file);
272 goto loser;
274 link_buf[ret] = 0;
275 link_file = mkoutput(input_file);
276 /* get the dirname of input_file */
277 dirpath = PORT_Strdup(input_file);
278 dirend = PORT_Strrchr(dirpath, '/');
279 if (dirend) {
280 *dirend = '\0';
281 ret = chdir(dirpath);
282 if (ret < 0) {
283 perror(dirpath);
284 goto loser;
287 PORT_Free(dirpath);
288 input_file = link_buf;
289 /* get the basename of link_file */
290 dirend = PORT_Strrchr(link_file, '/');
291 if (dirend) {
292 link_file = dirend + 1;
295 #endif
296 if (output_file == NULL) {
297 output_file = mkoutput(input_file);
300 hashcx = PK11_CreateDigestContext(SEC_OID_SHA1);
301 if (hashcx == NULL) {
302 lperror("SHA1 Digest Create");
303 goto loser;
306 /* hash the file */
307 while ((bytesRead = PR_Read(fd,file_buf,sizeof(file_buf))) > 0) {
308 PK11_DigestOp(hashcx,file_buf,bytesRead);
309 count += bytesRead;
312 PR_Close(fd);
313 fd = NULL;
314 if (bytesRead < 0) {
315 lperror(input_file);
316 goto loser;
320 PK11_DigestFinal(hashcx, hash.data, &hash.len, hash.len);
322 if (hash.len != SHA1_LENGTH) {
323 fprintf(stderr, "Digest length was not correct\n");
324 goto loser;
327 /* signe the hash */
328 rv = PK11_Sign(privk,&sign,&hash);
329 if (rv != SECSuccess) {
330 lperror("Signing");
331 goto loser;
334 if (verbose) {
335 int i,j;
336 fprintf(stderr,"Library File: %s %d bytes\n",input_file, count);
337 fprintf(stderr,"Check File: %s\n",output_file);
338 #ifdef USES_LINKS
339 if (link_file) {
340 fprintf(stderr,"Link: %s\n",link_file);
342 #endif
343 fprintf(stderr," hash: %d bytes\n", hash.len);
344 #define STEP 10
345 for (i=0; i < hash.len; i += STEP) {
346 fprintf(stderr," ");
347 for (j=0; j < STEP && (i+j) < hash.len; j++) {
348 fprintf(stderr," %02x", hash.data[i+j]);
350 fprintf(stderr,"\n");
352 fprintf(stderr," signature: %d bytes\n", sign.len);
353 for (i=0; i < sign.len; i += STEP) {
354 fprintf(stderr," ");
355 for (j=0; j < STEP && (i+j) < sign.len; j++) {
356 fprintf(stderr," %02x", sign.data[i+j]);
358 fprintf(stderr,"\n");
362 /* open the target signature file */
363 fd = PR_OpenFile(output_file,PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE,0666);
364 if (fd == NULL ) {
365 lperror(output_file);
366 goto loser;
370 * we write the key out in a straight binary format because very
371 * low level libraries need to read an parse this file. Ideally we should
372 * just derEncode the public key (which would be pretty simple, and be
373 * more general), but then we'd need to link the ASN.1 decoder with the
374 * freebl libraries.
377 file_buf[0] = NSS_SIGN_CHK_MAGIC1;
378 file_buf[1] = NSS_SIGN_CHK_MAGIC2;
379 file_buf[2] = NSS_SIGN_CHK_MAJOR_VERSION;
380 file_buf[3] = NSS_SIGN_CHK_MINOR_VERSION;
381 encodeInt(&file_buf[4],12); /* offset to data start */
382 encodeInt(&file_buf[8],CKK_DSA);
383 bytesWritten = PR_Write(fd,file_buf, 12);
384 if (bytesWritten != 12) {
385 lperror(output_file);
386 goto loser;
389 rv = writeItem(fd,&pubk->u.dsa.params.prime,output_file);
390 if (rv != SECSuccess) goto loser;
391 rv = writeItem(fd,&pubk->u.dsa.params.subPrime,output_file);
392 if (rv != SECSuccess) goto loser;
393 rv = writeItem(fd,&pubk->u.dsa.params.base,output_file);
394 if (rv != SECSuccess) goto loser;
395 rv = writeItem(fd,&pubk->u.dsa.publicValue,output_file);
396 if (rv != SECSuccess) goto loser;
397 rv = writeItem(fd,&sign,output_file);
398 if (rv != SECSuccess) goto loser;
400 PR_Close(fd);
402 #ifdef USES_LINKS
403 if (link_file) {
404 (void)unlink(link_file);
405 ret = symlink(output_file, link_file);
406 if (ret < 0) {
407 perror(link_file);
408 goto loser;
411 #endif
413 retval = 0;
415 loser:
416 if (hashcx) {
417 PK11_DestroyContext(hashcx, PR_TRUE);
419 if (privk) {
420 SECKEY_DestroyPrivateKey(privk);
422 if (pubk) {
423 SECKEY_DestroyPublicKey(pubk);
425 if (slot) {
426 PK11_FreeSlot(slot);
428 if (NSS_Shutdown() != SECSuccess) {
429 exit(1);
432 prdone:
433 PR_Cleanup ();
434 return retval;