nss: big cleanup in nss_load_cert() and cert_stuff()
This commit is contained in:
parent
052a08ff59
commit
06e6755e87
151
lib/nss.c
151
lib/nss.c
@ -319,6 +319,9 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl,
|
|||||||
CK_BBOOL ckfalse = CK_FALSE;
|
CK_BBOOL ckfalse = CK_FALSE;
|
||||||
CK_ATTRIBUTE attrs[/* max count of attributes */ 4];
|
CK_ATTRIBUTE attrs[/* max count of attributes */ 4];
|
||||||
int attr_cnt = 0;
|
int attr_cnt = 0;
|
||||||
|
CURLcode err = (cacert)
|
||||||
|
? CURLE_SSL_CACERT_BADFILE
|
||||||
|
: CURLE_SSL_CERTPROBLEM;
|
||||||
|
|
||||||
const int slot_id = (cacert) ? 0 : 1;
|
const int slot_id = (cacert) ? 0 : 1;
|
||||||
char *slot_name = aprintf("PEM Token #%d", slot_id);
|
char *slot_name = aprintf("PEM Token #%d", slot_id);
|
||||||
@ -328,7 +331,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl,
|
|||||||
slot = PK11_FindSlotByName(slot_name);
|
slot = PK11_FindSlotByName(slot_name);
|
||||||
free(slot_name);
|
free(slot_name);
|
||||||
if(!slot)
|
if(!slot)
|
||||||
return CURLE_SSL_CERTPROBLEM;
|
return err;
|
||||||
|
|
||||||
PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class));
|
PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class));
|
||||||
PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
|
PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
|
||||||
@ -343,7 +346,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl,
|
|||||||
obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE);
|
obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE);
|
||||||
PK11_FreeSlot(slot);
|
PK11_FreeSlot(slot);
|
||||||
if(!obj)
|
if(!obj)
|
||||||
return CURLE_SSL_CERTPROBLEM;
|
return err;
|
||||||
|
|
||||||
if(!Curl_llist_insert_next(ssl->obj_list, ssl->obj_list->tail, obj)) {
|
if(!Curl_llist_insert_next(ssl->obj_list, ssl->obj_list->tail, obj)) {
|
||||||
PK11_DestroyGenericObject(obj);
|
PK11_DestroyGenericObject(obj);
|
||||||
@ -368,77 +371,21 @@ static void nss_destroy_object(void *user, void *ptr)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int nss_load_cert(struct ssl_connect_data *ssl,
|
static CURLcode nss_load_cert(struct ssl_connect_data *ssl,
|
||||||
const char *filename, PRBool cacert)
|
const char *filename, PRBool cacert)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_PK11_CREATEGENERICOBJECT
|
CURLcode err = (cacert)
|
||||||
/* All CA and trust objects go into slot 0. Other slots are used
|
? CURLE_SSL_CACERT_BADFILE
|
||||||
* for storing certificates.
|
: CURLE_SSL_CERTPROBLEM;
|
||||||
*/
|
|
||||||
const int slot_id = (cacert) ? 0 : 1;
|
|
||||||
#endif
|
|
||||||
CERTCertificate *cert;
|
|
||||||
char *nickname = NULL;
|
|
||||||
char *n = NULL;
|
|
||||||
|
|
||||||
/* If there is no slash in the filename it is assumed to be a regular
|
|
||||||
* NSS nickname.
|
|
||||||
*/
|
|
||||||
if(is_file(filename)) {
|
|
||||||
n = strrchr(filename, '/');
|
|
||||||
if(n)
|
|
||||||
n++;
|
|
||||||
if(!mod)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* A nickname from the NSS internal database */
|
|
||||||
if(cacert)
|
|
||||||
return 0; /* You can't specify an NSS CA nickname this way */
|
|
||||||
nickname = strdup(filename);
|
|
||||||
if(!nickname)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_PK11_CREATEGENERICOBJECT
|
#ifdef HAVE_PK11_CREATEGENERICOBJECT
|
||||||
nickname = aprintf("PEM Token #%d:%s", slot_id, n);
|
/* libnsspem.so leaks memory if the requested file does not exist. For more
|
||||||
if(!nickname)
|
* details, go to <https://bugzilla.redhat.com/734760>. */
|
||||||
return 0;
|
if(is_file(filename))
|
||||||
|
return nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert);
|
||||||
if(CURLE_OK != nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert)) {
|
|
||||||
free(nickname);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
/* We don't have PK11_CreateGenericObject but a file-based cert was passed
|
|
||||||
* in. We need to fail.
|
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
done:
|
return err;
|
||||||
/* Double-check that the certificate or nickname requested exists in
|
|
||||||
* either the token or the NSS certificate database.
|
|
||||||
*/
|
|
||||||
if(!cacert) {
|
|
||||||
cert = PK11_FindCertFromNickname((char *)nickname, NULL);
|
|
||||||
|
|
||||||
/* An invalid nickname was passed in */
|
|
||||||
if(cert == NULL) {
|
|
||||||
free(nickname);
|
|
||||||
PR_SetError(SEC_ERROR_UNKNOWN_CERT, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CERT_DestroyCertificate(cert);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(nickname);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add given CRL to cache if it is not already there */
|
/* add given CRL to cache if it is not already there */
|
||||||
@ -527,23 +474,23 @@ fail:
|
|||||||
return SECFailure;
|
return SECFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nss_load_key(struct connectdata *conn, int sockindex,
|
static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
|
||||||
char *key_file)
|
char *key_file)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_PK11_CREATEGENERICOBJECT
|
#ifdef HAVE_PK11_CREATEGENERICOBJECT
|
||||||
PK11SlotInfo *slot;
|
PK11SlotInfo *slot;
|
||||||
SECStatus status;
|
SECStatus status;
|
||||||
struct ssl_connect_data *ssl = conn->ssl;
|
struct ssl_connect_data *ssl = conn->ssl;
|
||||||
(void)sockindex; /* unused */
|
|
||||||
|
|
||||||
if(CURLE_OK != nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE)) {
|
CURLcode rv = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE);
|
||||||
|
if(CURLE_OK != rv) {
|
||||||
PR_SetError(SEC_ERROR_BAD_KEY, 0);
|
PR_SetError(SEC_ERROR_BAD_KEY, 0);
|
||||||
return 0;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
slot = PK11_FindSlotByName("PEM Token #1");
|
slot = PK11_FindSlotByName("PEM Token #1");
|
||||||
if(!slot)
|
if(!slot)
|
||||||
return 0;
|
return CURLE_SSL_CERTPROBLEM;
|
||||||
|
|
||||||
/* This will force the token to be seen as re-inserted */
|
/* This will force the token to be seen as re-inserted */
|
||||||
SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
|
SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
|
||||||
@ -552,16 +499,18 @@ static int nss_load_key(struct connectdata *conn, int sockindex,
|
|||||||
status = PK11_Authenticate(slot, PR_TRUE,
|
status = PK11_Authenticate(slot, PR_TRUE,
|
||||||
conn->data->set.str[STRING_KEY_PASSWD]);
|
conn->data->set.str[STRING_KEY_PASSWD]);
|
||||||
PK11_FreeSlot(slot);
|
PK11_FreeSlot(slot);
|
||||||
return (SECSuccess == status) ? 1 : 0;
|
return (SECSuccess == status)
|
||||||
|
? CURLE_OK
|
||||||
|
: CURLE_SSL_CERTPROBLEM;
|
||||||
#else
|
#else
|
||||||
/* If we don't have PK11_CreateGenericObject then we can't load a file-based
|
/* If we don't have PK11_CreateGenericObject then we can't load a file-based
|
||||||
* key.
|
* key.
|
||||||
*/
|
*/
|
||||||
(void)conn; /* unused */
|
(void)conn; /* unused */
|
||||||
(void)key_file; /* unused */
|
(void)key_file; /* unused */
|
||||||
(void)sockindex; /* unused */
|
return CURLE_SSL_CERTPROBLEM;
|
||||||
return 0;
|
|
||||||
#endif
|
#endif
|
||||||
|
(void)sockindex; /* unused */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int display_error(struct connectdata *conn, PRInt32 err,
|
static int display_error(struct connectdata *conn, PRInt32 err,
|
||||||
@ -580,34 +529,37 @@ static int display_error(struct connectdata *conn, PRInt32 err,
|
|||||||
return 0; /* The caller will print a generic error */
|
return 0; /* The caller will print a generic error */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cert_stuff(struct connectdata *conn,
|
static CURLcode cert_stuff(struct connectdata *conn, int sockindex,
|
||||||
int sockindex, char *cert_file, char *key_file)
|
char *cert_file, char *key_file)
|
||||||
{
|
{
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
int rv = 0;
|
CURLcode rv;
|
||||||
|
|
||||||
if(cert_file) {
|
if(cert_file) {
|
||||||
rv = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
|
rv = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
|
||||||
if(!rv) {
|
if(CURLE_OK != rv) {
|
||||||
if(!display_error(conn, PR_GetError(), cert_file))
|
if(!display_error(conn, PR_GetError(), cert_file))
|
||||||
failf(data, "Unable to load client cert %d.", PR_GetError());
|
failf(data, "Unable to load client cert %d.", PR_GetError());
|
||||||
return 0;
|
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(key_file || (is_file(cert_file))) {
|
if(key_file || (is_file(cert_file))) {
|
||||||
if(key_file)
|
if(key_file)
|
||||||
rv = nss_load_key(conn, sockindex, key_file);
|
rv = nss_load_key(conn, sockindex, key_file);
|
||||||
else
|
else
|
||||||
/* In case the cert file also has the key */
|
/* In case the cert file also has the key */
|
||||||
rv = nss_load_key(conn, sockindex, cert_file);
|
rv = nss_load_key(conn, sockindex, cert_file);
|
||||||
if(!rv) {
|
if(CURLE_OK != rv) {
|
||||||
if(!display_error(conn, PR_GetError(), key_file))
|
if(!display_error(conn, PR_GetError(), key_file))
|
||||||
failf(data, "Unable to load client key %d.", PR_GetError());
|
failf(data, "Unable to load client key %d.", PR_GetError());
|
||||||
|
|
||||||
return 0;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
|
static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
|
||||||
@ -774,7 +726,6 @@ static SECStatus check_issuer_cert(PRFileDesc *sock,
|
|||||||
cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner);
|
cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner);
|
||||||
|
|
||||||
proto_win = SSL_RevealPinArg(sock);
|
proto_win = SSL_RevealPinArg(sock);
|
||||||
issuer = NULL;
|
|
||||||
issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
|
issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
|
||||||
|
|
||||||
if((!cert_issuer) || (!issuer))
|
if((!cert_issuer) || (!issuer))
|
||||||
@ -1132,8 +1083,11 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
|
|||||||
const char *cafile = data->set.ssl.CAfile;
|
const char *cafile = data->set.ssl.CAfile;
|
||||||
const char *capath = data->set.ssl.CApath;
|
const char *capath = data->set.ssl.CApath;
|
||||||
|
|
||||||
if(cafile && !nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE))
|
if(cafile) {
|
||||||
return CURLE_SSL_CACERT_BADFILE;
|
CURLcode rv = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
|
||||||
|
if(CURLE_OK != rv)
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
if(capath) {
|
if(capath) {
|
||||||
struct_stat st;
|
struct_stat st;
|
||||||
@ -1153,7 +1107,7 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
|
|||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
|
if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
|
||||||
/* This is purposefully tolerant of errors so non-PEM files can
|
/* This is purposefully tolerant of errors so non-PEM files can
|
||||||
* be in the same directory */
|
* be in the same directory */
|
||||||
infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath);
|
infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath);
|
||||||
@ -1349,10 +1303,21 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
|
|||||||
|
|
||||||
if(data->set.str[STRING_CERT]) {
|
if(data->set.str[STRING_CERT]) {
|
||||||
char *nickname = dup_nickname(data, STRING_CERT);
|
char *nickname = dup_nickname(data, STRING_CERT);
|
||||||
if(!nickname && !cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
|
if(nickname) {
|
||||||
data->set.str[STRING_KEY]))
|
/* we are not going to use libnsspem.so to read the client cert */
|
||||||
/* failf() is already done in cert_stuff() */
|
#ifdef HAVE_PK11_CREATEGENERICOBJECT
|
||||||
return CURLE_SSL_CERTPROBLEM;
|
connssl->obj_clicert = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
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 */
|
/* store the nickname for SelectClientCert() called during handshake */
|
||||||
connssl->client_nickname = nickname;
|
connssl->client_nickname = nickname;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user