enum okay ssl_open(const char *server, struct sock *sp, const char *uhp) { PRFileDesc *fdp, *fdc; if (nss_init() == STOP) return STOP; ssl_set_vrfy_level(uhp); nss_select_method(uhp); if ((fdp = PR_ImportTCPSocket(sp->s_fd)) == NULL) { nss_gen_err("Error importing OS file descriptor"); return STOP; } if ((fdc = SSL_ImportFD(NULL, fdp)) == NULL) { nss_gen_err("Error importing NSPR file descriptor"); PR_Close(fdp); return STOP; } SSL_SetURL(fdc, server); SSL_SetPKCS11PinArg(fdc, NULL); SSL_BadCertHook(fdc, bad_cert_cb, NULL); if (SSL_ResetHandshake(fdc, PR_FALSE) != SECSuccess) { nss_gen_err("Cannot reset NSS handshake"); PR_Close(fdc); return STOP; } if (SSL_ForceHandshake(fdc) != 0) { nss_gen_err("SSL/TLS handshake failed"); PR_Close(fdc); return STOP; } sp->s_prfd = fdc; if (nss_check_host(server, sp) != OKAY && ssl_vrfy_decide() != OKAY) { PR_Close(fdc); sp->s_prfd = NULL; return STOP; } sp->s_use_ssl = 1; if (verbose) { char *cipher, *issuer, *subject; int keysize, secretkeysize; if (SSL_SecurityStatus(fdc, NULL, &cipher, &keysize, &secretkeysize, &issuer, &subject) == SECSuccess) { fprintf(stderr, "SSL parameters: cipher=%s, " "keysize=%d, secretkeysize=%d,\n" "issuer=%s\n" "subject=%s\n", cipher, keysize, secretkeysize, issuer, subject); PR_Free(cipher); PR_Free(issuer); PR_Free(subject); } else nss_gen_err("Could not read status information"); } return OKAY; }
int cverify(void *vp) { int *msgvec = vp, *ip; int ec = 0; if (nss_init() != OKAY) return 1; ssl_vrfy_level = VRFY_STRICT; for (ip = msgvec; *ip; ip++) { setdot(&message[*ip-1]); ec |= verify1(&message[*ip-1], *ip); } return ec; }
CURLcode Curl_nss_force_init(struct SessionHandle *data) { CURLcode rv; if(!nss_initlock) { failf(data, "unable to initialize NSS, curl_global_init() should have been " "called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL"); return CURLE_FAILED_INIT; } PR_Lock(nss_initlock); rv = nss_init(data); PR_Unlock(nss_initlock); return rv; }
uint32_t as_new_sections(ElfObj *eo, void *mapped_address, uint32_t new_segment_vaddr, uint32_t new_segment_offset, uint32_t new_segment_size, // not known until third pass uint32_t new_pogo_section_size, uint32_t new_target_section_size, uint32_t relocated_sections_offset, uint32_t *extra_shstrtab_size, ElfWS_Ehdr *newEhdr) { NewSections nss_alloc, *nss=&nss_alloc; nss_init(nss, mapped_address, new_segment_vaddr, new_segment_offset, new_segment_size, 5, *extra_shstrtab_size); as_new_phdr(eo, nss, newEhdr); NewSection *ns_shdrs = as_new_shdr_alloc(eo, nss); NewSection *ns_shstrtab = as_new_shstrtab_alloc(eo, nss); (void) nss_alloc_section(nss, "pogo", new_pogo_section_size); (void) nss_alloc_section(nss, "target", new_target_section_size); as_new_shstrtab_fill(eo, nss, ns_shstrtab, newEhdr); as_new_shdr_fill(eo, nss, ns_shdrs, newEhdr, nss->num_new_sections, relocated_sections_offset); assert(nss->num_new_sections == nss->next_idx); // adjust num_new_sections parameter to match number of nss_alloc_sections calls if ((*extra_shstrtab_size)==0) { (*extra_shstrtab_size) = nss->extra_shstrtab_offset; } else { assert((*extra_shstrtab_size) == nss->extra_shstrtab_offset); assert((*extra_shstrtab_size) == nss->extra_shstrtab_size); } return nss->next_allocation; }
struct message * smime_decrypt(struct message *m, const char *to, const char *cc, int signcall) { NSSCMSDecoderContext *ctx; NSSCMSMessage *msg; FILE *op, *hp, *bp; char *buf = NULL; size_t bufsize = 0, buflen, count; char *cp; struct str in, out; FILE *yp; long size; int i, nlevels; int binary = 0; if ((yp = setinput(&mb, m, NEED_BODY)) == NULL) return NULL; if (nss_init() != OKAY) return NULL; if ((op = Ftemp(&cp, "Rp", "w+", 0600, 1)) == NULL) { perror("tempfile"); return NULL; } rm(cp); Ftfree(&cp); if ((ctx = NSS_CMSDecoder_Start(NULL, decoder_cb, op, password_cb, "Pass phrase:", NULL, NULL)) == NULL) { fprintf(stderr, "Cannot start decoder.\n"); return NULL; } size = m->m_size; if ((smime_split(yp, &hp, &bp, size, 1)) == STOP) return NULL; count = fsize(bp); while (fgetline(&buf, &bufsize, &count, &buflen, bp, 0) != NULL) { if (buf[0] == '\n') break; if ((cp = thisfield(buf, "content-transfer-encoding")) != NULL) if (ascncasecmp(cp, "binary", 7) == 0) binary = 1; } while (fgetline(&buf, &bufsize, &count, &buflen, bp, 0) != NULL) { if (binary) NSS_CMSDecoder_Update(ctx, buf, buflen); else { in.s = buf; in.l = buflen; mime_fromb64_b(&in, &out, 0, bp); NSS_CMSDecoder_Update(ctx, out.s, out.l); free(out.s); } } free(buf); if ((msg = NSS_CMSDecoder_Finish(ctx)) == NULL) { fprintf(stderr, "Failed to decode message.\n"); Fclose(hp); Fclose(bp); return NULL; } nlevels = NSS_CMSMessage_ContentLevelCount(msg); for (i = 0; i < nlevels; i++) { NSSCMSContentInfo *content; SECOidTag tag; content = NSS_CMSMessage_ContentLevel(msg, i); tag = NSS_CMSContentInfo_GetContentTypeTag(content); if (tag == SEC_OID_PKCS7_DATA) { const char *fld = "X-Encryption-Cipher"; SECOidTag alg; int keysize; alg = NSS_CMSContentInfo_GetContentEncAlgTag(content); keysize = NSS_CMSContentInfo_GetBulkKeySize(content); fseek(hp, 0L, SEEK_END); switch (alg) { case 0: if (signcall) { NSS_CMSMessage_Destroy(msg); Fclose(hp); Fclose(bp); setinput(&mb, m, NEED_BODY); return (struct message *)-1; } fprintf(hp, "%s: none\n", fld); break; case SEC_OID_RC2_CBC: fprintf(hp, "%s: RC2, %d bits\n", fld, keysize); break; case SEC_OID_DES_CBC: fprintf(hp, "%s: DES, 56 bits\n", fld); break; case SEC_OID_DES_EDE3_CBC: fprintf(hp, "%s: 3DES, 112/168 bits\n", fld); break; case SEC_OID_FORTEZZA_SKIPJACK: fprintf(hp, "%s: Fortezza\n", fld); break; default: fprintf(hp, "%s: unknown type %lu\n", fld, (unsigned long)alg); } fflush(hp); rewind(hp); } } NSS_CMSMessage_Destroy(msg); fflush(op); rewind(op); Fclose(bp); return smime_decrypt_assemble(m, hp, op); }
FILE * smime_encrypt(FILE *ip, const char *ignored, const char *to) { NSSCMSMessage *msg; NSSCMSContentInfo *content; NSSCMSEnvelopedData *data; NSSCMSRecipientInfo *info; CERTCertificate *cert[2]; CERTCertDBHandle *handle; SECOidTag tag; FILE *hp, *pp, *yp; int keysize; char *nickname, *vn; int vs; if (nss_init() != OKAY) return NULL; handle = CERT_GetDefaultCertDB(); vn = ac_alloc(vs = strlen(to) + 30); snprintf(vn, vs, "smime-nickname-%s", to); nickname = value(vn); ac_free(vn); if ((cert[0] = CERT_FindCertByNicknameOrEmailAddr(handle, nickname ? nickname : (char *)to)) == NULL) { if (nickname) fprintf(stderr, "Cannot find certificate \"%s\".\n", nickname); else fprintf(stderr, "Cannot find certificate for <%s>.\n", to); return NULL; } cert[1] = NULL; if (getcipher(to, &tag, &keysize) != OKAY) return NULL; if ((msg = NSS_CMSMessage_Create(NULL)) == NULL) { fprintf(stderr, "Cannot create CMS message.\n"); return NULL; } if ((data = NSS_CMSEnvelopedData_Create(msg, tag, keysize)) == NULL) { fprintf(stderr, "Cannot create enveloped data.\n"); return NULL; } content = NSS_CMSMessage_GetContentInfo(msg); if (NSS_CMSContentInfo_SetContent_EnvelopedData(msg, content, data) != SECSuccess) { fprintf(stderr, "Cannot attach enveloped data.\n"); return NULL; } content = NSS_CMSEnvelopedData_GetContentInfo(data); if (NSS_CMSContentInfo_SetContent_Data(msg, content, NULL, PR_FALSE) != SECSuccess) { fprintf(stderr, "Cannot attach CMS data.\n"); return NULL; } if ((info = NSS_CMSRecipientInfo_Create(msg, cert[0])) == NULL) { fprintf(stderr, "Cannot create CMS recipient information.\n"); return NULL; } if (NSS_CMSEnvelopedData_AddRecipient(data, info) != SECSuccess) { fprintf(stderr, "Cannot add CMS recipient information.\n"); return NULL; } CERT_DestroyCertificate(cert[0]); if ((yp = encode(ip, &hp, &pp, msg, base64_cb)) == NULL) return NULL; NSS_CMSMessage_Destroy(msg); return smime_encrypt_assemble(hp, yp); }
FILE * smime_sign(FILE *ip, struct header *headp) { NSSCMSMessage *msg; NSSCMSContentInfo *content; NSSCMSSignedData *data; NSSCMSSignerInfo *info; CERTCertificate *cert; CERTCertDBHandle *handle; FILE *hp, *bp, *sp; char *addr; if (nss_init() != OKAY) return NULL; if ((addr = myorigin(headp)) == NULL) { fprintf(stderr, "No \"from\" address for signing specified\n"); return NULL; } if ((cert = get_signer_cert(addr)) == NULL) return NULL; handle = CERT_GetDefaultCertDB(); if ((msg = NSS_CMSMessage_Create(NULL)) == NULL) { fprintf(stderr, "Cannot create CMS message.\n"); return NULL; } if ((data = NSS_CMSSignedData_Create(msg)) == NULL) { fprintf(stderr, "Cannot create CMS signed data.\n"); return NULL; } content = NSS_CMSMessage_GetContentInfo(msg); if (NSS_CMSContentInfo_SetContent_SignedData(msg, content, data) != SECSuccess) { fprintf(stderr, "Cannot attach CMS signed data.\n"); return NULL; } content = NSS_CMSSignedData_GetContentInfo(data); if (NSS_CMSContentInfo_SetContent_Data(msg, content, NULL, PR_TRUE) != SECSuccess) { fprintf(stderr, "Cannot attach CMS data.\n"); return NULL; } if ((info = NSS_CMSSignerInfo_Create(msg, cert, SEC_OID_SHA1)) == 0) { fprintf(stderr, "Cannot create signed information.\n"); return NULL; } if (NSS_CMSSignerInfo_IncludeCerts(info, NSSCMSCM_CertOnly, certUsageEmailSigner) != SECSuccess) { fprintf(stderr, "Cannot include certificate.\n"); return NULL; } if (NSS_CMSSignerInfo_AddSigningTime(info, PR_Now()) != SECSuccess) { fprintf(stderr, "Cannot add signing time.\n"); return NULL; } if (NSS_CMSSignerInfo_AddSMIMECaps(info) != SECSuccess) { fprintf(stderr, "Cannot add S/MIME capabilities.\n"); return NULL; } NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(info, cert, handle); NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(info, cert, handle); if (NSS_CMSSignedData_AddCertificate(data, cert) != SECSuccess) { fprintf(stderr, "Cannot add encryption certificate.\n"); return NULL; } if (NSS_CMSSignedData_AddSignerInfo(data, info) != SECSuccess) { fprintf(stderr, "Cannot add signer information.\n"); return NULL; } CERT_DestroyCertificate(cert); if ((sp = encode(ip, &hp, &bp, msg, base64_cb)) == NULL) { NSS_CMSMessage_Destroy(msg); return NULL; } NSS_CMSMessage_Destroy(msg); return smime_sign_assemble(hp, bp, sp); }
enum okay smime_certsave(struct message *m, int n, FILE *op) { NSSCMSMessage *msg; CERTCertDBHandle *handle; int nlevels, i, cnt = 0; enum okay ok = OKAY; if (nss_init() == STOP) return STOP; if ((m = getsig(m, n, &msg)) == NULL) return 1; handle = CERT_GetDefaultCertDB(); nlevels = NSS_CMSMessage_ContentLevelCount(msg); for (i = 0; i < nlevels; i++) { NSSCMSContentInfo *content; SECOidTag tag; content = NSS_CMSMessage_ContentLevel(msg, i); tag = NSS_CMSContentInfo_GetContentTypeTag(content); if (tag == SEC_OID_PKCS7_SIGNED_DATA) { NSSCMSSignedData *data; int nsigners, j; if ((data = NSS_CMSContentInfo_GetContent(content)) == NULL) { fprintf(stderr, "Signed data missing for " "message %d.\n", n); ok = STOP; break; } if (NSS_CMSSignedData_ImportCerts(data, handle, certUsageEmailSigner, PR_FALSE) != SECSuccess) { fprintf(stderr, "Cannot temporarily import " "certificates for " "message %d.\n", n); ok = STOP; break; } nsigners = NSS_CMSSignedData_SignerInfoCount(data); if (nsigners == 0) { fprintf(stderr, "Message %d has no signers.\n", n); ok = STOP; break; } for (j = 0; j < nsigners; j++) { NSSCMSSignerInfo *info; CERTCertificateList *list; CERTCertificate *cert; int k; info = NSS_CMSSignedData_GetSignerInfo(data, j); list = NSS_CMSSignerInfo_GetCertList(info); if (list) { for (k = 0; k < list->len; k++) { cert = (CERTCertificate *) &list->certs[k]; dumpcert(cert, op); cnt++; } } cert = NSS_CMSSignerInfo_GetSigningCertificate (info, handle); if (cert) { dumpcert(cert, op); cnt++; } } } } NSS_CMSMessage_Destroy(msg); if (cnt == 0) { fprintf(stderr, "No certificates found in message %d.\n", n); ok = STOP; } return ok; }
CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) { PRErrorCode err = 0; PRFileDesc *model = NULL; PRBool ssl2 = PR_FALSE; PRBool ssl3 = PR_FALSE; PRBool tlsv1 = PR_FALSE; PRBool ssl_no_cache; PRBool ssl_cbc_random_iv; struct SessionHandle *data = conn->data; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CURLcode curlerr; const int *cipher_to_enable; PRSocketOptionData sock_opt; long time_left; PRUint32 timeout; if(connssl->state == ssl_connection_complete) return CURLE_OK; connssl->data = data; /* list of all NSS objects we need to destroy in Curl_nss_close() */ connssl->obj_list = Curl_llist_alloc(nss_destroy_object); if(!connssl->obj_list) return CURLE_OUT_OF_MEMORY; /* FIXME. NSS doesn't support multiple databases open at the same time. */ PR_Lock(nss_initlock); curlerr = nss_init(conn->data); if(CURLE_OK != curlerr) { PR_Unlock(nss_initlock); goto error; } curlerr = CURLE_SSL_CONNECT_ERROR; if(!mod) { char *configstring = aprintf("library=%s name=PEM", pem_library); if(!configstring) { PR_Unlock(nss_initlock); goto error; } mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE); free(configstring); if(!mod || !mod->loaded) { if(mod) { SECMOD_DestroyModule(mod); mod = NULL; } infof(data, "WARNING: failed to load NSS PEM library %s. Using " "OpenSSL PEM certificates will not work.\n", pem_library); } } PK11_SetPasswordFunc(nss_get_password); PR_Unlock(nss_initlock); model = PR_NewTCPSocket(); if(!model) goto error; model = SSL_ImportFD(NULL, model); /* make the socket nonblocking */ sock_opt.option = PR_SockOpt_Nonblocking; sock_opt.value.non_blocking = PR_TRUE; if(PR_SetSocketOption(model, &sock_opt) != PR_SUCCESS) goto error; if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess) goto error; if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess) goto error; if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess) goto error; /* do not use SSL cache if we are not going to verify peer */ ssl_no_cache = (data->set.ssl.verifypeer) ? PR_FALSE : PR_TRUE; if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess) goto error; switch (data->set.ssl.version) { default: case CURL_SSLVERSION_DEFAULT: ssl3 = PR_TRUE; if(data->state.ssl_connect_retry) infof(data, "TLS disabled due to previous handshake failure\n"); else tlsv1 = PR_TRUE; break; case CURL_SSLVERSION_TLSv1: tlsv1 = PR_TRUE; break; case CURL_SSLVERSION_SSLv2: ssl2 = PR_TRUE; break; case CURL_SSLVERSION_SSLv3: ssl3 = PR_TRUE; break; } if(SSL_OptionSet(model, SSL_ENABLE_SSL2, ssl2) != SECSuccess) goto error; if(SSL_OptionSet(model, SSL_ENABLE_SSL3, ssl3) != SECSuccess) goto error; if(SSL_OptionSet(model, SSL_ENABLE_TLS, tlsv1) != SECSuccess) goto error; if(SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, ssl2) != SECSuccess) goto error; ssl_cbc_random_iv = !data->set.ssl_enable_beast; #ifdef SSL_CBC_RANDOM_IV /* unless the user explicitly asks to allow the protocol vulnerability, we use the work-around */ if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess) infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d\n", ssl_cbc_random_iv); #else if(ssl_cbc_random_iv) infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n"); #endif /* reset the flag to avoid an infinite loop */ data->state.ssl_connect_retry = FALSE; /* enable all ciphers from enable_ciphers_by_default */ cipher_to_enable = enable_ciphers_by_default; while(SSL_NULL_WITH_NULL_NULL != *cipher_to_enable) { if(SSL_CipherPrefSet(model, *cipher_to_enable, PR_TRUE) != SECSuccess) { curlerr = CURLE_SSL_CIPHER; goto error; } cipher_to_enable++; } if(data->set.ssl.cipher_list) { if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) { curlerr = CURLE_SSL_CIPHER; goto error; } } if(!data->set.ssl.verifypeer && data->set.ssl.verifyhost) infof(data, "warning: ignoring value of ssl.verifyhost\n"); /* bypass the default SSL_AuthCertificate() hook in case we do not want to * verify peer */ if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess) goto error; data->set.ssl.certverifyresult=0; /* not checked yet */ if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess) goto error; if(SSL_HandshakeCallback(model, HandshakeCallback, NULL) != SECSuccess) goto error; if(data->set.ssl.verifypeer) { const CURLcode rv = nss_load_ca_certificates(conn, sockindex); if(CURLE_OK != rv) { curlerr = rv; goto error; } } if(data->set.ssl.CRLfile) { if(SECSuccess != nss_load_crl(data->set.ssl.CRLfile)) { curlerr = CURLE_SSL_CRL_BADFILE; goto error; } infof(data, " CRLfile: %s\n", data->set.ssl.CRLfile ? data->set.ssl.CRLfile : "none"); } if(data->set.str[STRING_CERT]) { char *nickname = dup_nickname(data, STRING_CERT); if(nickname) { /* we are not going to use libnsspem.so to read the client cert */ connssl->obj_clicert = NULL; } else { CURLcode rv = cert_stuff(conn, sockindex, data->set.str[STRING_CERT], data->set.str[STRING_KEY]); if(CURLE_OK != rv) { /* failf() is already done in cert_stuff() */ curlerr = rv; goto error; } } /* store the nickname for SelectClientCert() called during handshake */ connssl->client_nickname = nickname; } else connssl->client_nickname = NULL; if(SSL_GetClientAuthDataHook(model, SelectClientCert, (void *)connssl) != SECSuccess) { curlerr = CURLE_SSL_CERTPROBLEM; goto error; } /* Import our model socket onto the existing file descriptor */ connssl->handle = PR_ImportTCPSocket(sockfd); connssl->handle = SSL_ImportFD(model, connssl->handle); if(!connssl->handle) goto error; PR_Close(model); /* We don't need this any more */ model = NULL; /* This is the password associated with the cert that we're using */ if(data->set.str[STRING_KEY_PASSWD]) { SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]); } /* Force handshake on next I/O */ SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE); SSL_SetURL(connssl->handle, conn->host.name); /* check timeout situation */ time_left = Curl_timeleft(data, NULL, TRUE); if(time_left < 0L) { failf(data, "timed out before SSL handshake"); curlerr = CURLE_OPERATION_TIMEDOUT; goto error; } timeout = PR_MillisecondsToInterval((PRUint32) time_left); /* Force the handshake now */ if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) { if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) curlerr = CURLE_PEER_FAILED_VERIFICATION; else if(conn->data->set.ssl.certverifyresult!=0) curlerr = CURLE_SSL_CACERT; goto error; } connssl->state = ssl_connection_complete; conn->recv[sockindex] = nss_recv; conn->send[sockindex] = nss_send; display_conn_info(conn, connssl->handle); if(data->set.str[STRING_SSL_ISSUERCERT]) { SECStatus ret = SECFailure; char *nickname = dup_nickname(data, STRING_SSL_ISSUERCERT); if(nickname) { /* we support only nicknames in case of STRING_SSL_ISSUERCERT for now */ ret = check_issuer_cert(connssl->handle, nickname); free(nickname); } if(SECFailure == ret) { infof(data,"SSL certificate issuer check failed\n"); curlerr = CURLE_SSL_ISSUER_ERROR; goto error; } else { infof(data, "SSL certificate issuer check ok\n"); } } return CURLE_OK; error: /* reset the flag to avoid an infinite loop */ data->state.ssl_connect_retry = FALSE; if(is_nss_error(curlerr)) { /* read NSPR error code */ err = PR_GetError(); if(is_cc_error(err)) curlerr = CURLE_SSL_CERTPROBLEM; /* print the error number and error string */ infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err)); /* print a human-readable message describing the error if available */ nss_print_error_message(data, err); } if(model) PR_Close(model); /* cleanup on connection failure */ Curl_llist_destroy(connssl->obj_list, NULL); connssl->obj_list = NULL; if(ssl3 && tlsv1 && isTLSIntoleranceError(err)) { /* schedule reconnect through Curl_retry_request() */ data->state.ssl_connect_retry = TRUE; infof(data, "Error in TLS handshake, trying SSLv3...\n"); return CURLE_OK; } return curlerr; }