// nsPKCS12Blob::ExportToFile // // Having already loaded the certs, form them into a blob (loading the keys // also), encode the blob, and stuff it into the file. // // TODO: handle slots correctly // mirror "slotToUse" behavior from PSM 1.x // verify the cert array to start off with? // open output file as nsIFileStream object? // set appropriate error codes nsresult nsPKCS12Blob::ExportToFile(nsILocalFile *file, nsIX509Cert **certs, int numCerts) { nsNSSShutDownPreventionLock locker; nsresult rv; SECStatus srv = SECSuccess; SEC_PKCS12ExportContext *ecx = NULL; SEC_PKCS12SafeInfo *certSafe = NULL, *keySafe = NULL; SECItem unicodePw; nsAutoString filePath; int i; nsCOMPtr<nsILocalFile> localFileRef; NS_ASSERTION(mToken, "Need to set the token before exporting"); // init slot PRBool InformedUserNoSmartcardBackup = PR_FALSE; int numCertsExported = 0; rv = mToken->Login(PR_TRUE); if (NS_FAILED(rv)) goto finish; // get file password (unicode) unicodePw.data = NULL; rv = newPKCS12FilePassword(&unicodePw); if (NS_FAILED(rv)) goto finish; if (unicodePw.data == NULL) { handleError(PIP_PKCS12_USER_CANCELED); return NS_OK; } // what about slotToUse in psm 1.x ??? // create export context ecx = SEC_PKCS12CreateExportContext(NULL, NULL, NULL /*slot*/, NULL); if (!ecx) { srv = SECFailure; goto finish; } // add password integrity srv = SEC_PKCS12AddPasswordIntegrity(ecx, &unicodePw, SEC_OID_SHA1); if (srv) goto finish; #if 0 // count the number of certs to export nrv = mCertArray->Count(&numCerts); if (NS_FAILED(nrv)) goto finish; // loop over the certs for (i=0; i<numCerts; i++) { nsCOMPtr<nsIX509Cert> cert; nrv = mCertArray->GetElementAt(i, getter_AddRefs(cert)); if (NS_FAILED(nrv)) goto finish; #endif for (i=0; i<numCerts; i++) { // nsNSSCertificate *cert = reinterpret_cast<nsNSSCertificate *>(certs[i]); nsNSSCertificate *cert = (nsNSSCertificate *)certs[i]; // get it as a CERTCertificate XXX CERTCertificate *nssCert = NULL; CERTCertificateCleaner nssCertCleaner(nssCert); nssCert = cert->GetCert(); if (!nssCert) { rv = NS_ERROR_FAILURE; goto finish; } // We can only successfully export certs that are on // internal token. Most, if not all, smart card vendors // won't let you extract the private key (in any way // shape or form) from the card. So let's punt if // the cert is not in the internal db. if (nssCert->slot && !PK11_IsInternal(nssCert->slot)) { // we aren't the internal token, see if the key is extractable. SECKEYPrivateKey *privKey=PK11_FindKeyByDERCert(nssCert->slot, nssCert, this); if (privKey) { PRBool privKeyIsExtractable = isExtractable(privKey); SECKEY_DestroyPrivateKey(privKey); if (!privKeyIsExtractable) { if (!InformedUserNoSmartcardBackup) { InformedUserNoSmartcardBackup = PR_TRUE; handleError(PIP_PKCS12_NOSMARTCARD_EXPORT); } continue; } } } // XXX this is why, to verify the slot is the same // PK11_FindObjectForCert(nssCert, NULL, slot); // create the cert and key safes keySafe = SEC_PKCS12CreateUnencryptedSafe(ecx); if (!SEC_PKCS12IsEncryptionAllowed() || PK11_IsFIPS()) { certSafe = keySafe; } else { certSafe = SEC_PKCS12CreatePasswordPrivSafe(ecx, &unicodePw, SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC); } if (!certSafe || !keySafe) { rv = NS_ERROR_FAILURE; goto finish; } // add the cert and key to the blob srv = SEC_PKCS12AddCertAndKey(ecx, certSafe, NULL, nssCert, CERT_GetDefaultCertDB(), // XXX keySafe, NULL, PR_TRUE, &unicodePw, SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC); if (srv) goto finish; // cert was dup'ed, so release it ++numCertsExported; } if (!numCertsExported) goto finish; // prepare the instance to write to an export file this->mTmpFile = NULL; file->GetPath(filePath); // Use the nsCOMPtr var localFileRef so that // the reference to the nsILocalFile we create gets released as soon as // we're out of scope, ie when this function exits. if (filePath.RFind(".p12", PR_TRUE, -1, 4) < 0) { // We're going to add the .p12 extension to the file name just like // Communicator used to. We create a new nsILocalFile and initialize // it with the new patch. filePath.AppendLiteral(".p12"); localFileRef = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); if (NS_FAILED(rv)) goto finish; localFileRef->InitWithPath(filePath); file = localFileRef; } rv = file->OpenNSPRFileDesc(PR_RDWR|PR_CREATE_FILE|PR_TRUNCATE, 0664, &mTmpFile); if (NS_FAILED(rv) || !this->mTmpFile) goto finish; // encode and write srv = SEC_PKCS12Encode(ecx, write_export_file, this); if (srv) goto finish; handleError(PIP_PKCS12_BACKUP_OK); finish: if (NS_FAILED(rv) || srv != SECSuccess) { handleError(PIP_PKCS12_BACKUP_FAILED); } if (ecx) SEC_PKCS12DestroyExportContext(ecx); if (this->mTmpFile) { PR_Close(this->mTmpFile); this->mTmpFile = NULL; } return rv; } /////////////////////////////////////////////////////////////////////// // // private members // /////////////////////////////////////////////////////////////////////// // unicodeToItem // // For the NSS PKCS#12 library, must convert PRUnichars (shorts) to // a buffer of octets. Must handle byte order correctly. // TODO: Is there a mozilla way to do this? In the string lib? void nsPKCS12Blob::unicodeToItem(const PRUnichar *uni, SECItem *item) { int len = 0; while (uni[len++] != 0); SECITEM_AllocItem(NULL, item, sizeof(PRUnichar) * len); #ifdef IS_LITTLE_ENDIAN int i = 0; for (i=0; i<len; i++) { item->data[2*i ] = (unsigned char )(uni[i] << 8); item->data[2*i+1] = (unsigned char )(uni[i]); } #else memcpy(item->data, uni, item->len); #endif }
static void AcceptThread(void *arg) { PRIntervalTime timeout = (PRIntervalTime) arg; PRIntervalTime elapsed; #if defined(XP_UNIX) || defined(WIN32) PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); PRInt32 elapsed_msecs; #endif #if defined(XP_UNIX) struct timeval end_time_tv; #endif #if defined(WIN32) struct _timeb end_time_tb; #endif PRFileDesc *sock; PRNetAddr addr; PRFileDesc *accepted; sock = PR_NewTCPSocket(); if (sock == NULL) { fprintf(stderr, "PR_NewTCPSocket failed\n"); exit(1); } memset(&addr, 0, sizeof(addr)); addr.inet.family = PR_AF_INET; addr.inet.port = 0; addr.inet.ip = PR_htonl(PR_INADDR_ANY); if (PR_Bind(sock, &addr) == PR_FAILURE) { fprintf(stderr, "PR_Bind failed\n"); exit(1); } if (PR_Listen(sock, 5) == PR_FAILURE) { fprintf(stderr, "PR_Listen failed\n"); exit(1); } accepted = PR_Accept(sock, NULL, timeout); if (accepted != NULL || PR_GetError() != PR_IO_TIMEOUT_ERROR) { fprintf(stderr, "PR_Accept did not time out\n"); exit(1); } elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { fprintf(stderr, "timeout wrong\n"); exit(1); } #if defined(XP_UNIX) gettimeofday(&end_time_tv, NULL); elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec) + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000; #endif #if defined(WIN32) _ftime(&end_time_tb); elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time) + (end_time_tb.millitm - start_time_tb.millitm); #endif #if defined(XP_UNIX) || defined(WIN32) if (elapsed_msecs + tolerance_msecs < timeout_msecs || elapsed_msecs > timeout_msecs + tolerance_msecs) { fprintf(stderr, "timeout wrong\n"); exit(1); } #endif if (PR_Close(sock) == PR_FAILURE) { fprintf(stderr, "PR_Close failed\n"); exit(1); } if (debug_mode) { fprintf(stderr, "Accept thread (scope %d) done\n", PR_GetThreadScope(PR_GetCurrentThread())); } }
int main(int argc, char **argv) { PRHostEnt hostentry; char buf[PR_NETDB_BUF_SIZE]; PRNetAddr addr; PRFileDesc *socket = NULL, *file = NULL; PRIntn cmdSize; char host[HOST_SIZE]; char port[PORT_SIZE]; char path[PATH_SIZE]; char line[LINE_SIZE]; int exitStatus = 0; PRBool endOfHeader = PR_FALSE; char *url; char *fileName = NULL; PRUint32 fileSize; if (argc != 2 && argc != 4) { PrintUsage(); exit(1); } if (argc == 2) { /* * case 1: httpget url */ url = argv[1]; } else { if (strcmp(argv[1], "-o") == 0) { /* * case 2: httpget -o outputfile url */ fileName = argv[2]; url = argv[3]; } else { /* * case 3: httpget url -o outputfile */ url = argv[1]; if (strcmp(argv[2], "-o") != 0) { PrintUsage(); exit(1); } fileName = argv[3]; } } if (ParseURL(url, host, sizeof(host), port, sizeof(port), path, sizeof(path)) == PR_FAILURE) { exit(1); } if (PR_GetHostByName(host, buf, sizeof(buf), &hostentry) == PR_FAILURE) { fprintf(stderr, "httpget: unknown host name: %s\n", host); exit(1); } addr.inet.family = PR_AF_INET; addr.inet.port = PR_htons((short) atoi(port)); addr.inet.ip = *((PRUint32 *) hostentry.h_addr_list[0]); socket = PR_NewTCPSocket(); if (socket == NULL) { fprintf(stderr, "httpget: cannot create new tcp socket\n"); exit(1); } if (PR_Connect(socket, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { fprintf(stderr, "httpget: cannot connect to http server\n"); exitStatus = 1; goto done; } if (fileName == NULL) { file = PR_STDOUT; } else { file = PR_Open(fileName, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00777); if (file == NULL) { fprintf(stderr, "httpget: cannot open file %s: (%d, %d)\n", fileName, PR_GetError(), PR_GetOSError()); exitStatus = 1; goto done; } } cmdSize = PR_snprintf(buf, sizeof(buf), "GET %s HTTP/1.0\r\n\r\n", path); PR_ASSERT(cmdSize == (PRIntn) strlen("GET HTTP/1.0\r\n\r\n") + (PRIntn) strlen(path)); if (PR_Write(socket, buf, cmdSize) != cmdSize) { fprintf(stderr, "httpget: cannot write to http server\n"); exitStatus = 1; goto done; } if (ReadLine(socket, line, sizeof(line)) <= 0) { fprintf(stderr, "httpget: cannot read line from http server\n"); exitStatus = 1; goto done; } /* HTTP response: 200 == OK */ if (strstr(line, "200") == NULL) { fprintf(stderr, "httpget: %s\n", line); exitStatus = 1; goto done; } while (ReadLine(socket, line, sizeof(line)) > 0) { if (line[0] == '\n') { endOfHeader = PR_TRUE; break; } if (strncmp(line, "Content-Length", 14) == 0 || strncmp(line, "Content-length", 14) == 0) { char *p = line + 14; while (*p == ' ' || *p == '\t') { p++; } if (*p != ':') { continue; } p++; while (*p == ' ' || *p == '\t') { p++; } fileSize = 0; while ('0' <= *p && *p <= '9') { fileSize = 10 * fileSize + (*p - '0'); p++; } } } if (endOfHeader == PR_FALSE) { fprintf(stderr, "httpget: cannot read line from http server\n"); exitStatus = 1; goto done; } if (fileName == NULL || fileSize == 0) { FetchFile(socket, file); } else { FastFetchFile(socket, file, fileSize); } done: if (socket) PR_Close(socket); if (file) PR_Close(file); PR_Cleanup(); return exitStatus; }