pk1sign.c (8077B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /* 6 * pk1sign 7 */ 8 9 #include "nspr.h" 10 #include "plgetopt.h" 11 #include "secutil.h" 12 #include "secpkcs7.h" 13 #include "cert.h" 14 #include "certdb.h" 15 #include "sechash.h" /* for HASH_GetHashObject() */ 16 #include "nss.h" 17 #include "pk11func.h" 18 #include "cryptohi.h" 19 #include "plbase64.h" 20 21 #if defined(XP_UNIX) 22 #include <unistd.h> 23 #endif 24 25 #include <stdio.h> 26 #include <string.h> 27 28 #if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4)) 29 extern int fread(char *, size_t, size_t, FILE *); 30 extern int fwrite(char *, size_t, size_t, FILE *); 31 extern int fprintf(FILE *, char *, ...); 32 #endif 33 34 static secuPWData pwdata = { PW_NONE, 0 }; 35 36 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) 37 38 SEC_ASN1Template CERTSignatureDataTemplate[] = { 39 { SEC_ASN1_SEQUENCE, 40 0, NULL, sizeof(CERTSignedData) }, 41 { SEC_ASN1_INLINE, 42 offsetof(CERTSignedData, signatureAlgorithm), 43 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 44 { SEC_ASN1_BIT_STRING, 45 offsetof(CERTSignedData, signature) }, 46 { 0 } 47 }; 48 49 static void 50 Usage(char *progName) 51 { 52 fprintf(stderr, 53 "Usage: %s -k keyname [-d keydir] [-i input] [-o output]\n", 54 progName); 55 fprintf(stderr, "%-20s Nickname of key to use for signature\n", 56 "-k keyname"); 57 fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", 58 "-d keydir"); 59 fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", 60 "-i input"); 61 fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", 62 "-o output"); 63 fprintf(stderr, "%-20s Password to the key databse\n", "-p"); 64 fprintf(stderr, "%-20s password file\n", "-f"); 65 exit(-1); 66 } 67 68 static int 69 ExportPublicKey(FILE *outFile, CERTCertificate *cert) 70 { 71 char *data; 72 SECKEYPublicKey *publicKey; 73 SECItem *item; 74 75 if (!cert) 76 return -1; 77 78 publicKey = CERT_ExtractPublicKey(cert); 79 if (!publicKey) 80 return -1; 81 82 item = SECKEY_EncodeDERSubjectPublicKeyInfo(publicKey); 83 SECKEY_DestroyPublicKey(publicKey); 84 if (!item) 85 return -1; 86 87 data = PL_Base64Encode((const char *)item->data, item->len, NULL); 88 SECITEM_FreeItem(item, PR_TRUE); 89 if (!data) 90 return -1; 91 92 fputs("pubkey:\n", outFile); 93 fputs(data, outFile); 94 fputs("\n", outFile); 95 PR_Free(data); 96 97 return 0; 98 } 99 100 static int 101 SignFile(FILE *outFile, PRFileDesc *inFile, CERTCertificate *cert) 102 { 103 SECItem data2sign; 104 SECStatus rv; 105 SECOidTag algID; 106 CERTSignedData sd; 107 SECKEYPrivateKey *privKey = NULL; 108 char *data = NULL; 109 PLArenaPool *arena = NULL; 110 SECItem *result = NULL; 111 int returnValue = 0; 112 113 if (outFile == NULL || inFile == NULL || cert == NULL) { 114 return -1; 115 } 116 117 /* suck the file in */ 118 if (SECU_ReadDERFromFile(&data2sign, inFile, PR_FALSE, 119 PR_FALSE) != SECSuccess) { 120 return -1; 121 } 122 123 privKey = NULL; 124 privKey = PK11_FindKeyByAnyCert(cert, NULL); 125 if (!privKey) { 126 returnValue = -1; 127 goto loser; 128 } 129 130 algID = SEC_GetSignatureAlgorithmOidTagByKey(privKey, NULL, SEC_OID_UNKNOWN); 131 if (algID == SEC_OID_UNKNOWN) { 132 returnValue = -1; 133 goto loser; 134 } 135 136 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 137 138 PORT_Memset(&sd, 0, sizeof(CERTSignedData)); 139 140 rv = SEC_SignData(&(sd.signature), data2sign.data, data2sign.len, privKey, algID); 141 if (rv != SECSuccess) { 142 fprintf(stderr, "Could not sign.\n"); 143 returnValue = -1; 144 goto loser; 145 } 146 sd.signature.len = sd.signature.len << 3; 147 148 rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0); 149 if (rv != SECSuccess) { 150 fprintf(stderr, "Could not set alg id.\n"); 151 returnValue = -1; 152 goto loser; 153 } 154 155 result = SEC_ASN1EncodeItem(arena, NULL, &sd, CERTSignatureDataTemplate); 156 SECITEM_FreeItem(&(sd.signature), PR_FALSE); 157 158 if (!result) { 159 fprintf(stderr, "Could not encode.\n"); 160 returnValue = -1; 161 goto loser; 162 } 163 164 data = PL_Base64Encode((const char *)result->data, result->len, NULL); 165 if (!data) { 166 returnValue = -1; 167 goto loser; 168 } 169 170 fputs("signature:\n", outFile); 171 fputs(data, outFile); 172 fputs("\n", outFile); 173 ExportPublicKey(outFile, cert); 174 175 loser: 176 if (privKey) { 177 SECKEY_DestroyPrivateKey(privKey); 178 } 179 if (data) { 180 PR_Free(data); 181 } 182 PORT_FreeArena(arena, PR_FALSE); 183 184 return returnValue; 185 } 186 187 int 188 main(int argc, char **argv) 189 { 190 char *progName; 191 FILE *outFile; 192 PRFileDesc *inFile; 193 char *keyName = NULL; 194 CERTCertDBHandle *certHandle; 195 CERTCertificate *cert = NULL; 196 PLOptState *optstate; 197 PLOptStatus status; 198 SECStatus rv; 199 200 progName = strrchr(argv[0], '/'); 201 progName = progName ? progName + 1 : argv[0]; 202 203 inFile = NULL; 204 outFile = NULL; 205 keyName = NULL; 206 207 /* 208 * Parse command line arguments 209 */ 210 optstate = PL_CreateOptState(argc, argv, "ed:k:i:o:p:f:"); 211 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { 212 switch (optstate->option) { 213 case '?': 214 Usage(progName); 215 break; 216 217 case 'd': 218 SECU_ConfigDirectory(optstate->value); 219 break; 220 221 case 'i': 222 inFile = PR_Open(optstate->value, PR_RDONLY, 0); 223 if (!inFile) { 224 fprintf(stderr, "%s: unable to open \"%s\" for reading\n", 225 progName, optstate->value); 226 return -1; 227 } 228 break; 229 230 case 'k': 231 keyName = strdup(optstate->value); 232 break; 233 234 case 'o': 235 outFile = fopen(optstate->value, "wb"); 236 if (!outFile) { 237 fprintf(stderr, "%s: unable to open \"%s\" for writing\n", 238 progName, optstate->value); 239 return -1; 240 } 241 break; 242 case 'p': 243 pwdata.source = PW_PLAINTEXT; 244 pwdata.data = strdup(optstate->value); 245 break; 246 247 case 'f': 248 pwdata.source = PW_FROMFILE; 249 pwdata.data = PORT_Strdup(optstate->value); 250 break; 251 } 252 } 253 254 if (!keyName) 255 Usage(progName); 256 257 if (!inFile) 258 inFile = PR_STDIN; 259 if (!outFile) 260 outFile = stdout; 261 262 /* Call the initialization routines */ 263 PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); 264 rv = NSS_Init(SECU_ConfigDirectory(NULL)); 265 if (rv != SECSuccess) { 266 SECU_PrintPRandOSError(progName); 267 goto loser; 268 } 269 270 PK11_SetPasswordFunc(SECU_GetModulePassword); 271 272 /* open cert database */ 273 certHandle = CERT_GetDefaultCertDB(); 274 if (certHandle == NULL) { 275 rv = SECFailure; 276 goto loser; 277 } 278 279 /* find cert */ 280 cert = CERT_FindCertByNickname(certHandle, keyName); 281 if (cert == NULL) { 282 SECU_PrintError(progName, 283 "the corresponding cert for key \"%s\" does not exist", 284 keyName); 285 rv = SECFailure; 286 goto loser; 287 } 288 289 if (SignFile(outFile, inFile, cert)) { 290 SECU_PrintError(progName, "problem signing data"); 291 rv = SECFailure; 292 goto loser; 293 } 294 295 loser: 296 if (pwdata.data) { 297 PORT_Free(pwdata.data); 298 } 299 if (keyName) { 300 PORT_Free(keyName); 301 } 302 if (cert) { 303 CERT_DestroyCertificate(cert); 304 } 305 if (inFile && inFile != PR_STDIN) { 306 PR_Close(inFile); 307 } 308 if (outFile && outFile != stdout) { 309 fclose(outFile); 310 } 311 if (NSS_Shutdown() != SECSuccess) { 312 SECU_PrintError(progName, "NSS shutdown:"); 313 exit(1); 314 } 315 316 return (rv != SECSuccess); 317 }