2010-06-26 08:31:24 -04:00
|
|
|
/*
|
|
|
|
* libretroshare/src/pqi: sslfns.cc
|
|
|
|
*
|
|
|
|
* 3P/PQI network interface for RetroShare.
|
|
|
|
*
|
|
|
|
* Copyright 2004-2008 by Robert Fernie.
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License Version 2 as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
|
|
* USA.
|
|
|
|
*
|
|
|
|
* Please report all bugs and problems to "retroshare@lunamutt.com".
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Functions in this file are SSL only,
|
|
|
|
* and have no dependence on SSLRoot() etc.
|
|
|
|
* might need SSL_Init() to be called - thats it!
|
|
|
|
*/
|
|
|
|
|
|
|
|
/******************** notify of new Cert **************************/
|
|
|
|
|
|
|
|
#include "pqi/sslfns.h"
|
|
|
|
#include "pqi/pqi_base.h"
|
2011-04-03 19:11:38 -04:00
|
|
|
#include "util/rsdir.h"
|
2012-04-13 20:30:23 -04:00
|
|
|
#include "util/rsstring.h"
|
2010-06-26 08:31:24 -04:00
|
|
|
|
|
|
|
#include <openssl/ssl.h>
|
|
|
|
#include <openssl/err.h>
|
|
|
|
#include <openssl/pem.h>
|
|
|
|
#include <openssl/rand.h>
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
/****
|
|
|
|
* #define AUTHSSL_DEBUG 1
|
|
|
|
***/
|
|
|
|
|
|
|
|
/********************************************************************************/
|
2010-07-10 16:34:03 -04:00
|
|
|
|
|
|
|
#if defined(SSLFNS_ADD_CIPHER_CTX_RAND_KEY)
|
|
|
|
|
|
|
|
int EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key)
|
|
|
|
{
|
|
|
|
//if (ctx->cipher->flags & EVP_CIPH_RAND_KEY)
|
|
|
|
// return EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_RAND_KEY, 0, key);
|
|
|
|
if (RAND_bytes(key, ctx->key_len) <= 0)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2010-06-26 08:31:24 -04:00
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
|
|
|
|
X509_REQ *GenerateX509Req(
|
|
|
|
std::string pkey_file, std::string passwd,
|
|
|
|
std::string name, std::string email, std::string org,
|
|
|
|
std::string loc, std::string state, std::string country,
|
|
|
|
int nbits_in, std::string &errString)
|
|
|
|
{
|
2015-10-20 21:03:08 -04:00
|
|
|
/* generate request */
|
|
|
|
X509_REQ *req=X509_REQ_new();
|
|
|
|
|
|
|
|
// setup output.
|
|
|
|
BIO *bio_out = BIO_new(BIO_s_file());
|
|
|
|
BIO_set_fp(bio_out,stdout,BIO_NOCLOSE);
|
|
|
|
|
|
|
|
EVP_PKEY *pkey = NULL;
|
|
|
|
X509_NAME *x509_name = NULL ;
|
|
|
|
RSA *rsa = NULL ;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// first generate a key....
|
|
|
|
if ((pkey=EVP_PKEY_new()) == NULL)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"GenerateX509Req: Couldn't Create Key\n");
|
|
|
|
throw std::runtime_error("Couldn't Create Key") ;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nbits = 2048;
|
|
|
|
unsigned long e = 0x10001;
|
|
|
|
|
|
|
|
if ((nbits_in >= 512) && (nbits_in <= 4096))
|
|
|
|
{
|
|
|
|
nbits = nbits_in;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr,"GenerateX509Req: strange num of nbits: %d\n", nbits_in);
|
|
|
|
fprintf(stderr,"GenerateX509Req: reverting to %d\n", nbits);
|
|
|
|
}
|
|
|
|
|
|
|
|
rsa = RSA_generate_key(nbits, e, NULL, NULL);
|
|
|
|
|
|
|
|
if ((rsa == NULL) || !EVP_PKEY_assign_RSA(pkey, rsa))
|
|
|
|
throw std::runtime_error("Couldn't generate RSA Key");
|
|
|
|
|
|
|
|
// open the file.
|
|
|
|
FILE *out;
|
|
|
|
if (NULL == (out = RsDirUtil::rs_fopen(pkey_file.c_str(), "w")))
|
|
|
|
throw std::runtime_error("Couldn't Create Key File \"" + pkey_file + "\"");
|
|
|
|
|
|
|
|
const EVP_CIPHER *cipher = EVP_des_ede3_cbc();
|
|
|
|
|
|
|
|
if (!PEM_write_PrivateKey(out,pkey,cipher, NULL,0,NULL,(void *) passwd.c_str()))
|
|
|
|
{
|
|
|
|
fclose(out) ;
|
|
|
|
throw std::runtime_error("Couldn't Save Private Key to file \""+pkey_file+"\"");
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(out);
|
|
|
|
|
|
|
|
// We have now created a private key....
|
|
|
|
std::cerr << "GenerateX509Req() Saved Private Key to file \"" << pkey_file << "\"" << std::endl;
|
|
|
|
|
|
|
|
/********** Test Loading the private Key.... ************/
|
|
|
|
FILE *tst_in = NULL;
|
|
|
|
EVP_PKEY *tst_pkey = NULL;
|
|
|
|
|
|
|
|
if (NULL == (tst_in = RsDirUtil::rs_fopen(pkey_file.c_str(), "rb")))
|
|
|
|
throw std::runtime_error("GenerateX509Req() Couldn't Open Private Key file \""+pkey_file+"\"") ;
|
|
|
|
|
|
|
|
if (NULL == (tst_pkey = PEM_read_PrivateKey(tst_in,NULL,NULL,(void *) passwd.c_str())))
|
|
|
|
{
|
|
|
|
fclose(tst_in);
|
|
|
|
throw std::runtime_error("GenerateX509Req() Couldn't read Private Key file \""+pkey_file+"\"") ;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(tst_in);
|
|
|
|
EVP_PKEY_free(tst_pkey);
|
|
|
|
|
|
|
|
/* Fill in details: fields.
|
2010-06-26 08:31:24 -04:00
|
|
|
req->req_info;
|
|
|
|
req->req_info->enc;
|
|
|
|
req->req_info->version;
|
|
|
|
req->req_info->subject;
|
|
|
|
req->req_info->pubkey;
|
|
|
|
****************************/
|
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
long version = 0x00;
|
|
|
|
unsigned long chtype = MBSTRING_UTF8;
|
|
|
|
x509_name = X509_NAME_new();
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
// fill in the request.
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
/**** X509_REQ -> Version ********************************/
|
|
|
|
if(!X509_REQ_set_version(req,version)) /* version 1 */
|
|
|
|
throw std::runtime_error("GenerateX509Req(): Couldn't Set SSL certificate Version!");
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
/**** X509_REQ -> Version ********************************/
|
|
|
|
/**** X509_REQ -> Key ********************************/
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
if (!X509_REQ_set_pubkey(req,pkey))
|
|
|
|
throw std::runtime_error("GenerateX509Req(): Couldn't Set SSL certificate PUBKEY!");
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
/**** SUBJECT ********************************/
|
|
|
|
// create the name.
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
// fields to add.
|
|
|
|
// commonName CN
|
|
|
|
// emailAddress (none)
|
|
|
|
// organizationName O
|
|
|
|
// localityName L
|
|
|
|
// stateOrProvinceName ST
|
|
|
|
// countryName C
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
if (0 == strlen(name.c_str()))
|
|
|
|
throw std::runtime_error("No name! Aborting.") ;
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
X509_NAME_add_entry_by_txt(x509_name, "CN", chtype, (unsigned char *) name.c_str(), -1, -1, 0);
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
if (0 < strlen(email.c_str()))
|
|
|
|
X509_NAME_add_entry_by_NID(x509_name, 48, 0, (unsigned char *) email.c_str(), -1, -1, 0);
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
if (0 < strlen(org.c_str()))
|
|
|
|
X509_NAME_add_entry_by_txt(x509_name, "O", chtype, (unsigned char *) org.c_str(), -1, -1, 0);
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
if (0 < strlen(loc.c_str()))
|
|
|
|
X509_NAME_add_entry_by_txt(x509_name, "L", chtype, (unsigned char *) loc.c_str(), -1, -1, 0);
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
if (0 < strlen(state.c_str()))
|
|
|
|
X509_NAME_add_entry_by_txt(x509_name, "ST", chtype, (unsigned char *) state.c_str(), -1, -1, 0);
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
if (0 < strlen(country.c_str()))
|
|
|
|
X509_NAME_add_entry_by_txt(x509_name, "C", chtype, (unsigned char *) country.c_str(), -1, -1, 0);
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
if (!X509_REQ_set_subject_name(req,x509_name))
|
|
|
|
throw std::runtime_error("GenerateX509Req() Couldn't Set Name to Request!");
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
X509_NAME_free(x509_name);
|
|
|
|
|
|
|
|
/**** SUBJECT ********************************/
|
|
|
|
|
|
|
|
if (!X509_REQ_sign(req,pkey,EVP_sha1()))
|
|
|
|
throw std::runtime_error("GenerateX509Req() Failed to sign REQ");
|
|
|
|
|
|
|
|
errString = "No Error";
|
|
|
|
|
|
|
|
return req;
|
|
|
|
}
|
|
|
|
catch(std::exception& e)
|
|
|
|
{
|
|
|
|
std::cerr << "(EE) Key creation failed: " << e.what() << std::endl;
|
|
|
|
errString = e.what() ;
|
|
|
|
req = NULL ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(rsa)
|
|
|
|
RSA_free(rsa);
|
|
|
|
|
|
|
|
if(x509_name)
|
|
|
|
X509_NAME_free(x509_name);
|
|
|
|
|
|
|
|
if(bio_out)
|
|
|
|
BIO_free_all(bio_out) ;
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2015-10-20 21:03:08 -04:00
|
|
|
if(pkey)
|
|
|
|
EVP_PKEY_free(pkey);
|
|
|
|
|
|
|
|
return req ;
|
2010-06-26 08:31:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#define SERIAL_RAND_BITS 64
|
|
|
|
|
|
|
|
X509 *SignX509Certificate(X509_NAME *issuer, EVP_PKEY *privkey, X509_REQ *req, long days)
|
|
|
|
{
|
|
|
|
const EVP_MD *digest = EVP_sha1();
|
|
|
|
ASN1_INTEGER *serial = ASN1_INTEGER_new();
|
|
|
|
EVP_PKEY *tmppkey;
|
|
|
|
X509 *x509 = X509_new();
|
|
|
|
if (x509 == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
BIGNUM *btmp = BN_new();
|
|
|
|
if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
|
|
|
|
{
|
|
|
|
fprintf(stderr,"SignX509Certificate() Failed: ");
|
|
|
|
fprintf(stderr," pseudo_rand\n");
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (!BN_to_ASN1_INTEGER(btmp, serial))
|
|
|
|
{
|
|
|
|
fprintf(stderr,"SignX509Certificate() Failed: ");
|
|
|
|
fprintf(stderr," int\n");
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
BN_free(btmp);
|
|
|
|
|
|
|
|
if (!X509_set_serialNumber(x509, serial))
|
|
|
|
{
|
|
|
|
fprintf(stderr,"SignX509Certificate() Failed: ");
|
|
|
|
fprintf(stderr," serialNumber\n");
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ASN1_INTEGER_free(serial);
|
|
|
|
|
|
|
|
if (!X509_set_issuer_name(x509, issuer))
|
|
|
|
{
|
|
|
|
fprintf(stderr,"SignX509Certificate() Failed: ");
|
|
|
|
fprintf(stderr," issuer\n");
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!X509_gmtime_adj(x509->cert_info->validity->notBefore, 0))
|
|
|
|
{
|
|
|
|
fprintf(stderr,"SignX509Certificate() Failed: ");
|
|
|
|
fprintf(stderr," notBefore\n");
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//x509->cert_info->validity->notAfter
|
|
|
|
//if (!X509_gmtime_adj(X509_get_notAfter(x509), (long)60*60*24*days))
|
|
|
|
if (!X509_gmtime_adj(x509->cert_info->validity->notAfter, (long)60*60*24*days))
|
|
|
|
{
|
|
|
|
fprintf(stderr,"SignX509Certificate() Failed: ");
|
|
|
|
fprintf(stderr," notAfter\n");
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!X509_set_subject_name(x509, X509_REQ_get_subject_name(req)))
|
|
|
|
{
|
|
|
|
fprintf(stderr,"SignX509Certificate() Failed: ");
|
|
|
|
fprintf(stderr," subject_name\n");
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tmppkey = X509_REQ_get_pubkey(req);
|
|
|
|
if (!tmppkey || !X509_set_pubkey(x509,tmppkey))
|
|
|
|
{
|
|
|
|
fprintf(stderr,"SignX509Certificate() Failed: ");
|
|
|
|
fprintf(stderr," pubkey\n");
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Cleanup Algorithm part */
|
|
|
|
|
|
|
|
X509_ALGOR *algor1 = x509->cert_info->signature;
|
|
|
|
X509_ALGOR *algor2 = x509->sig_alg;
|
|
|
|
|
|
|
|
X509_ALGOR *a;
|
|
|
|
|
|
|
|
a = algor1;
|
|
|
|
ASN1_TYPE_free(a->parameter);
|
|
|
|
a->parameter=ASN1_TYPE_new();
|
|
|
|
a->parameter->type=V_ASN1_NULL;
|
|
|
|
|
|
|
|
ASN1_OBJECT_free(a->algorithm);
|
|
|
|
a->algorithm=OBJ_nid2obj(digest->pkey_type);
|
|
|
|
|
|
|
|
a = algor2;
|
|
|
|
ASN1_TYPE_free(a->parameter);
|
|
|
|
a->parameter=ASN1_TYPE_new();
|
|
|
|
a->parameter->type=V_ASN1_NULL;
|
|
|
|
|
|
|
|
ASN1_OBJECT_free(a->algorithm);
|
|
|
|
a->algorithm=OBJ_nid2obj(digest->pkey_type);
|
|
|
|
|
|
|
|
|
|
|
|
if (!X509_sign(x509,privkey,digest))
|
|
|
|
{
|
|
|
|
long e = ERR_get_error();
|
|
|
|
|
|
|
|
fprintf(stderr,"SignX509Certificate() Failed: ");
|
|
|
|
fprintf(stderr," signing Error: %ld\n", e);
|
|
|
|
|
|
|
|
fprintf(stderr,"ERR: %s, %s, %s\n",
|
|
|
|
ERR_lib_error_string(e),
|
|
|
|
ERR_func_error_string(e),
|
|
|
|
ERR_reason_error_string(e));
|
|
|
|
|
|
|
|
int inl=i2d_X509(x509,NULL);
|
|
|
|
int outl=EVP_PKEY_size(privkey);
|
|
|
|
fprintf(stderr,"Size Check: inl: %d, outl: %d\n", inl, outl);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr,"SignX509Certificate() Success\n");
|
|
|
|
|
|
|
|
return x509;
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
/* Sign / Encrypt / Verify Data */
|
|
|
|
bool SSL_SignDataBin(const void *data, const uint32_t len,
|
|
|
|
unsigned char *sign, unsigned int *signlen, EVP_PKEY *pkey)
|
|
|
|
{
|
|
|
|
EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
|
|
|
|
unsigned int req_signlen = EVP_PKEY_size(pkey);
|
|
|
|
if (req_signlen > *signlen)
|
|
|
|
{
|
|
|
|
/* not enough space */
|
|
|
|
std::cerr << "SignDataBin() Not Enough Sign SpacegnInit Failure!" << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0 == EVP_SignInit(mdctx, EVP_sha1()))
|
|
|
|
{
|
|
|
|
std::cerr << "EVP_SignInit Failure!" << std::endl;
|
|
|
|
|
|
|
|
EVP_MD_CTX_destroy(mdctx);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0 == EVP_SignUpdate(mdctx, data, len))
|
|
|
|
{
|
|
|
|
std::cerr << "EVP_SignUpdate Failure!" << std::endl;
|
|
|
|
|
|
|
|
EVP_MD_CTX_destroy(mdctx);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0 == EVP_SignFinal(mdctx, sign, signlen, pkey))
|
|
|
|
{
|
|
|
|
std::cerr << "EVP_SignFinal Failure!" << std::endl;
|
|
|
|
|
|
|
|
EVP_MD_CTX_destroy(mdctx);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
EVP_MD_CTX_destroy(mdctx);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SSL_VerifySignBin(const void *data, const uint32_t len,
|
|
|
|
unsigned char *sign, unsigned int signlen, X509 *cert)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* cert->cert_info->key->pkey is NULL....
|
|
|
|
* but is instantiated when we call X509_get_pubkey()
|
|
|
|
*/
|
|
|
|
|
|
|
|
EVP_PKEY *peerkey = X509_get_pubkey(cert);
|
|
|
|
|
|
|
|
/* must free this key afterwards */
|
|
|
|
bool ret = SSL_VerifySignBin(data, len, sign, signlen, peerkey);
|
|
|
|
|
|
|
|
EVP_PKEY_free(peerkey);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Correct form of this function ... Internal for AuthSSL's usage
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool SSL_VerifySignBin(const void *data, const uint32_t len,
|
|
|
|
unsigned char *sign, unsigned int signlen, EVP_PKEY *peerkey)
|
|
|
|
{
|
|
|
|
if(peerkey == NULL)
|
|
|
|
{
|
|
|
|
std::cerr << "VerifySignBin: no public key available !!" << std::endl ;
|
|
|
|
return false ;
|
|
|
|
}
|
|
|
|
|
|
|
|
EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
|
|
|
|
|
|
|
|
if (0 == EVP_VerifyInit(mdctx, EVP_sha1()))
|
|
|
|
{
|
|
|
|
std::cerr << "EVP_VerifyInit Failure!" << std::endl;
|
|
|
|
|
|
|
|
EVP_MD_CTX_destroy(mdctx);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0 == EVP_VerifyUpdate(mdctx, data, len))
|
|
|
|
{
|
|
|
|
std::cerr << "EVP_VerifyUpdate Failure!" << std::endl;
|
|
|
|
|
|
|
|
EVP_MD_CTX_destroy(mdctx);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(signlen == 0 || sign == NULL)
|
|
|
|
{
|
|
|
|
std::cerr << "AuthSSL::VerifySignBin: signlen=" << signlen << ", sign=" << (void*)sign << "!!" << std::endl ;
|
|
|
|
EVP_MD_CTX_destroy(mdctx);
|
|
|
|
return false ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0 == EVP_VerifyFinal(mdctx, sign, signlen, peerkey))
|
|
|
|
{
|
|
|
|
std::cerr << "EVP_VerifyFinal Failure!" << std::endl;
|
|
|
|
|
|
|
|
EVP_MD_CTX_destroy(mdctx);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
EVP_MD_CTX_destroy(mdctx);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
|
|
|
|
X509 *loadX509FromPEM(std::string pem)
|
|
|
|
{
|
|
|
|
#ifdef AUTHSSL_DEBUG
|
|
|
|
std::cerr << "loadX509FromPEM()";
|
|
|
|
std::cerr << std::endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Put the data into a mem BIO */
|
|
|
|
char *certstr = strdup(pem.c_str());
|
|
|
|
|
|
|
|
BIO *bp = BIO_new_mem_buf(certstr, -1);
|
|
|
|
|
|
|
|
X509 *pc = PEM_read_bio_X509(bp, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
BIO_free(bp);
|
|
|
|
free(certstr);
|
|
|
|
|
|
|
|
return pc;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string saveX509ToPEM(X509* x509)
|
|
|
|
{
|
|
|
|
#ifdef AUTHSSL_DEBUG
|
|
|
|
std::cerr << "saveX509ToPEM() " << std::endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* get the cert first */
|
|
|
|
std::string certstr;
|
|
|
|
BIO *bp = BIO_new(BIO_s_mem());
|
|
|
|
|
|
|
|
PEM_write_bio_X509(bp, x509);
|
|
|
|
|
|
|
|
/* translate the bp data to a string */
|
|
|
|
char *data;
|
|
|
|
int len = BIO_get_mem_data(bp, &data);
|
|
|
|
for(int i = 0; i < len; i++)
|
|
|
|
{
|
|
|
|
certstr += data[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
BIO_free(bp);
|
|
|
|
|
|
|
|
return certstr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
X509 *loadX509FromDER(const uint8_t *ptr, uint32_t len)
|
|
|
|
{
|
|
|
|
#ifdef AUTHSSL_DEBUG
|
|
|
|
std::cerr << "AuthSSL::LoadX509FromDER()";
|
|
|
|
std::cerr << std::endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
X509 *tmp = NULL;
|
|
|
|
#ifdef __APPLE__
|
2011-06-29 14:02:44 -04:00
|
|
|
// This depends on which version you are compiling for... OSX10.5 doesn't have consts (old OpenSSL!)
|
2012-07-27 08:28:40 -04:00
|
|
|
// With the Advent of Openpgpsdk, we are forced to move to OSX10.6 for a newer OpenSSL (probably a good thing).
|
|
|
|
// So we can change this around.
|
|
|
|
//unsigned char **certptr = (unsigned char **) &ptr;
|
|
|
|
const unsigned char **certptr = (const unsigned char **) &ptr;
|
2010-06-26 08:31:24 -04:00
|
|
|
#else
|
|
|
|
const unsigned char **certptr = (const unsigned char **) &ptr;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
X509 *x509 = d2i_X509(&tmp, certptr, len);
|
|
|
|
|
|
|
|
return x509;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool saveX509ToDER(X509 *x509, uint8_t **ptr, uint32_t *len)
|
|
|
|
{
|
|
|
|
#ifdef AUTHSSL_DEBUG
|
|
|
|
std::cerr << "AuthSSL::saveX509ToDER()";
|
|
|
|
std::cerr << std::endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int certlen = i2d_X509(x509, (unsigned char **) ptr);
|
|
|
|
if (certlen > 0)
|
|
|
|
{
|
|
|
|
*len = certlen;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*len = 0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-17 16:56:06 -04:00
|
|
|
bool getX509id(X509 *x509, RsPeerId& xid)
|
|
|
|
{
|
2010-06-26 08:31:24 -04:00
|
|
|
#ifdef AUTHSSL_DEBUG
|
|
|
|
std::cerr << "AuthSSL::getX509id()";
|
|
|
|
std::cerr << std::endl;
|
|
|
|
#endif
|
|
|
|
|
2014-03-17 16:56:06 -04:00
|
|
|
xid.clear() ;
|
2010-06-26 08:31:24 -04:00
|
|
|
if (x509 == NULL)
|
|
|
|
{
|
|
|
|
#ifdef AUTHSSL_DEBUG
|
|
|
|
std::cerr << "AuthSSL::getX509id() NULL pointer";
|
|
|
|
std::cerr << std::endl;
|
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the signature from the cert, and copy to the array.
|
|
|
|
ASN1_BIT_STRING *signature = x509->signature;
|
|
|
|
int signlen = ASN1_STRING_length(signature);
|
|
|
|
if (signlen < CERTSIGNLEN)
|
|
|
|
{
|
|
|
|
#ifdef AUTHSSL_DEBUG
|
|
|
|
std::cerr << "AuthSSL::getX509id() ERROR: Short Signature";
|
|
|
|
std::cerr << std::endl;
|
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// else copy in the first CERTSIGNLEN.
|
|
|
|
unsigned char *signdata = ASN1_STRING_data(signature);
|
2012-04-13 20:30:23 -04:00
|
|
|
|
2010-06-26 08:31:24 -04:00
|
|
|
/* switched to the other end of the signature. for
|
|
|
|
* more randomness
|
|
|
|
*/
|
2014-03-17 16:56:06 -04:00
|
|
|
|
|
|
|
xid = RsPeerId(&signdata[signlen - CERTSIGNLEN]) ;
|
|
|
|
|
|
|
|
//for(int i = signlen - CERTSIGNLEN; i < signlen; i++)
|
|
|
|
//{
|
|
|
|
// rs_sprintf_append(xid, "%02x", (uint16_t) (((uint8_t *) (signdata))[i]));
|
|
|
|
//}
|
2012-04-13 20:30:23 -04:00
|
|
|
|
2010-06-26 08:31:24 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
/********************************************************************************/
|
|
|
|
|
|
|
|
int pem_passwd_cb(char *buf, int size, int rwflag, void *password)
|
|
|
|
{
|
|
|
|
/* remove unused parameter warnings */
|
|
|
|
(void) rwflag;
|
|
|
|
|
|
|
|
strncpy(buf, (char *)(password), size);
|
|
|
|
buf[size - 1] = '\0';
|
|
|
|
return(strlen(buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX FIX */
|
2011-08-12 09:42:30 -04:00
|
|
|
bool CheckX509Certificate(X509 */*x509*/)
|
2010-06-26 08:31:24 -04:00
|
|
|
{
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Not dependent on sslroot. load, and detroys the X509 memory.
|
2014-03-17 16:56:06 -04:00
|
|
|
int LoadCheckX509(const char *cert_file, RsPgpId& issuerName, std::string &location, RsPeerId &userId)
|
2010-06-26 08:31:24 -04:00
|
|
|
{
|
|
|
|
/* This function loads the X509 certificate from the file,
|
|
|
|
* and checks the certificate
|
|
|
|
*/
|
|
|
|
|
2011-04-03 19:11:38 -04:00
|
|
|
FILE *tmpfp = RsDirUtil::rs_fopen(cert_file, "r");
|
2010-06-26 08:31:24 -04:00
|
|
|
if (tmpfp == NULL)
|
|
|
|
{
|
|
|
|
#ifdef AUTHSSL_DEBUG
|
|
|
|
std::cerr << "sslroot::LoadCheckAndGetX509Name()";
|
|
|
|
std::cerr << " Failed to open Certificate File:" << cert_file;
|
|
|
|
std::cerr << std::endl;
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get xPGP certificate.
|
|
|
|
X509 *x509 = PEM_read_X509(tmpfp, NULL, NULL, NULL);
|
|
|
|
fclose(tmpfp);
|
|
|
|
|
|
|
|
// check the certificate.
|
|
|
|
bool valid = false;
|
|
|
|
if (x509)
|
|
|
|
{
|
|
|
|
valid = CheckX509Certificate(x509);
|
|
|
|
if (valid)
|
|
|
|
{
|
|
|
|
valid = getX509id(x509, userId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (valid)
|
|
|
|
{
|
|
|
|
// extract the name.
|
2014-03-17 16:56:06 -04:00
|
|
|
issuerName = RsPgpId(std::string(getX509CNString(x509->cert_info->issuer)));
|
2010-06-26 08:31:24 -04:00
|
|
|
location = getX509LocString(x509->cert_info->subject);
|
|
|
|
}
|
|
|
|
|
2012-04-19 18:10:00 -04:00
|
|
|
#ifdef AUTHSSL_DEBUG
|
2010-06-26 08:31:24 -04:00
|
|
|
std::cout << getX509Info(x509) << std::endl ;
|
2012-04-19 18:10:00 -04:00
|
|
|
#endif
|
2010-06-26 08:31:24 -04:00
|
|
|
// clean up.
|
|
|
|
X509_free(x509);
|
|
|
|
|
|
|
|
if (valid)
|
|
|
|
{
|
|
|
|
// happy!
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// something went wrong!
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getX509NameString(X509_NAME *name)
|
|
|
|
{
|
|
|
|
std::string namestr;
|
|
|
|
for(int i = 0; i < X509_NAME_entry_count(name); i++)
|
|
|
|
{
|
|
|
|
X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i);
|
|
|
|
ASN1_STRING *entry_data = X509_NAME_ENTRY_get_data(entry);
|
|
|
|
ASN1_OBJECT *entry_obj = X509_NAME_ENTRY_get_object(entry);
|
|
|
|
|
|
|
|
namestr += "\t";
|
|
|
|
namestr += OBJ_nid2ln(OBJ_obj2nid(entry_obj));
|
|
|
|
namestr += " : ";
|
|
|
|
|
|
|
|
//namestr += entry_obj -> flags;
|
|
|
|
//namestr += entry_data -> length;
|
|
|
|
//namestr += entry_data -> type;
|
|
|
|
|
|
|
|
//namestr += entry_data -> flags;
|
|
|
|
//entry -> set;
|
|
|
|
|
|
|
|
if (entry_data -> data != NULL)
|
|
|
|
{
|
|
|
|
namestr += (char *) entry_data -> data;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
namestr += "NULL";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i + 1 < X509_NAME_entry_count(name))
|
|
|
|
{
|
|
|
|
namestr += "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return namestr;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getX509CNString(X509_NAME *name)
|
|
|
|
{
|
|
|
|
std::string namestr;
|
|
|
|
for(int i = 0; i < X509_NAME_entry_count(name); i++)
|
|
|
|
{
|
|
|
|
X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i);
|
|
|
|
ASN1_STRING *entry_data = X509_NAME_ENTRY_get_data(entry);
|
|
|
|
ASN1_OBJECT *entry_obj = X509_NAME_ENTRY_get_object(entry);
|
|
|
|
|
|
|
|
if (0 == strncmp("CN", OBJ_nid2sn(OBJ_obj2nid(entry_obj)), 2))
|
|
|
|
{
|
|
|
|
if (entry_data -> data != NULL)
|
|
|
|
{
|
2014-12-03 18:03:03 -05:00
|
|
|
// do we need to convert ASN1_STRING to utf8 (ASN1_STRING_to_UTF8)?
|
|
|
|
namestr = (char *) entry_data->data;
|
2010-06-26 08:31:24 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-12-03 18:03:03 -05:00
|
|
|
namestr = "Unknown";
|
2010-06-26 08:31:24 -04:00
|
|
|
}
|
2014-12-03 18:03:03 -05:00
|
|
|
break;
|
2010-06-26 08:31:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return namestr;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getX509TypeString(X509_NAME *name, const char *type, int len)
|
|
|
|
{
|
|
|
|
std::string namestr;
|
|
|
|
for(int i = 0; i < X509_NAME_entry_count(name); i++)
|
|
|
|
{
|
|
|
|
X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i);
|
|
|
|
ASN1_STRING *entry_data = X509_NAME_ENTRY_get_data(entry);
|
|
|
|
ASN1_OBJECT *entry_obj = X509_NAME_ENTRY_get_object(entry);
|
|
|
|
|
|
|
|
if (0 == strncmp(type, OBJ_nid2sn(OBJ_obj2nid(entry_obj)), len))
|
|
|
|
{
|
|
|
|
if (entry_data -> data != NULL)
|
|
|
|
{
|
2014-12-03 18:03:03 -05:00
|
|
|
// do we need to convert ASN1_STRING to utf8 (ASN1_STRING_to_UTF8)?
|
|
|
|
namestr = (char *) entry_data -> data;
|
2010-06-26 08:31:24 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-12-03 18:03:03 -05:00
|
|
|
namestr = "Unknown";
|
2010-06-26 08:31:24 -04:00
|
|
|
}
|
2014-12-03 18:03:03 -05:00
|
|
|
break;
|
2010-06-26 08:31:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return namestr;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getX509LocString(X509_NAME *name)
|
|
|
|
{
|
|
|
|
return getX509TypeString(name, "L", 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getX509OrgString(X509_NAME *name)
|
|
|
|
{
|
|
|
|
return getX509TypeString(name, "O", 2);
|
|
|
|
}
|
2014-12-03 18:03:03 -05:00
|
|
|
|
2010-06-26 08:31:24 -04:00
|
|
|
std::string getX509CountryString(X509_NAME *name)
|
|
|
|
{
|
|
|
|
return getX509TypeString(name, "C", 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-19 18:10:00 -04:00
|
|
|
#ifdef AUTHSSL_DEBUG
|
2010-06-26 08:31:24 -04:00
|
|
|
std::string getX509Info(X509 *cert)
|
|
|
|
{
|
2012-04-19 18:10:00 -04:00
|
|
|
std::string out = "X509 Certificate:\n";
|
2010-06-26 08:31:24 -04:00
|
|
|
|
2012-04-19 18:10:00 -04:00
|
|
|
long l;
|
2010-06-26 08:31:24 -04:00
|
|
|
l=X509_get_version(cert);
|
2012-04-19 18:10:00 -04:00
|
|
|
rs_sprintf_append(out, " Version: %ld(0x%ld)\n", l+1, l);
|
|
|
|
out += " Subject: \n";
|
|
|
|
out += " " + getX509NameString(cert->cert_info->subject) + "\n\n";
|
|
|
|
out += " Signatures:\n";
|
|
|
|
return out;
|
2010-06-26 08:31:24 -04:00
|
|
|
}
|
2012-04-19 18:10:00 -04:00
|
|
|
#endif
|
2010-06-26 08:31:24 -04:00
|
|
|
|
|
|
|
/********** SSL ERROR STUFF ******************************************/
|
|
|
|
|
2012-04-13 20:30:23 -04:00
|
|
|
int printSSLError(SSL *ssl, int retval, int err, unsigned long err2, std::string &out)
|
2010-06-26 08:31:24 -04:00
|
|
|
{
|
|
|
|
(void) ssl; /* remove unused parameter warnings */
|
|
|
|
|
|
|
|
std::string reason;
|
|
|
|
|
|
|
|
std::string mainreason = std::string("UNKNOWN ERROR CODE");
|
|
|
|
if (err == SSL_ERROR_NONE)
|
|
|
|
{
|
|
|
|
mainreason = std::string("SSL_ERROR_NONE");
|
|
|
|
}
|
|
|
|
else if (err == SSL_ERROR_ZERO_RETURN)
|
|
|
|
{
|
|
|
|
mainreason = std::string("SSL_ERROR_ZERO_RETURN");
|
|
|
|
}
|
|
|
|
else if (err == SSL_ERROR_WANT_READ)
|
|
|
|
{
|
|
|
|
mainreason = std::string("SSL_ERROR_WANT_READ");
|
|
|
|
}
|
|
|
|
else if (err == SSL_ERROR_WANT_WRITE)
|
|
|
|
{
|
|
|
|
mainreason = std::string("SSL_ERROR_WANT_WRITE");
|
|
|
|
}
|
|
|
|
else if (err == SSL_ERROR_WANT_CONNECT)
|
|
|
|
{
|
|
|
|
mainreason = std::string("SSL_ERROR_WANT_CONNECT");
|
|
|
|
}
|
|
|
|
else if (err == SSL_ERROR_WANT_ACCEPT)
|
|
|
|
{
|
|
|
|
mainreason = std::string("SSL_ERROR_WANT_ACCEPT");
|
|
|
|
}
|
|
|
|
else if (err == SSL_ERROR_WANT_X509_LOOKUP)
|
|
|
|
{
|
|
|
|
mainreason = std::string("SSL_ERROR_WANT_X509_LOOKUP");
|
|
|
|
}
|
|
|
|
else if (err == SSL_ERROR_SYSCALL)
|
|
|
|
{
|
|
|
|
mainreason = std::string("SSL_ERROR_SYSCALL");
|
|
|
|
}
|
|
|
|
else if (err == SSL_ERROR_SSL)
|
|
|
|
{
|
|
|
|
mainreason = std::string("SSL_ERROR_SSL");
|
|
|
|
}
|
2012-04-13 20:30:23 -04:00
|
|
|
rs_sprintf_append(out, "RetVal(%d) -> SSL Error: %s\n\t + ERR Error: %s\n", retval, mainreason.c_str(), ERR_error_string(err2, NULL));
|
2010-06-26 08:31:24 -04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|