ensured maximum backward compatibility for crypto changes that will occur in future v0.7

This commit is contained in:
csoler 2017-11-22 00:02:11 +01:00
parent e2c1661c49
commit f6d69e09d5
4 changed files with 137 additions and 73 deletions

View File

@ -708,7 +708,6 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
#define SERIAL_RAND_BITS 64
//const EVP_MD *digest = EVP_sha1();
ASN1_INTEGER *serial = ASN1_INTEGER_new();
EVP_PKEY *tmppkey;
X509 *x509 = X509_new();
if (x509 == NULL)
@ -733,12 +732,28 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
std::cerr << "AuthSSLimpl::SignX509Req() Issuer name: " << AuthGPG::getAuthGPG()->getGPGOwnId().toStdString() << std::endl;
#ifdef V07_NON_BACKWARD_COMPATIBLE_CHANGE_002
static const uint64_t CERTIFICATE_SERIAL_NUMBER = RS_CERTIFICATE_VERSION_NUMBER_07_0001 ;
#else
#ifdef V07_NON_BACKWARD_COMPATIBLE_CHANGE_001
static const uint64_t CERTIFICATE_SERIAL_NUMBER = RS_CERTIFICATE_VERSION_NUMBER_06_0001 ;
#else
static const uint64_t CERTIFICATE_SERIAL_NUMBER = RS_CERTIFICATE_VERSION_NUMBER_06_0000 ;
#endif
#endif
BIGNUM *btmp = BN_new();
BN_set_word(btmp,CERTIFICATE_SERIAL_NUMBER) ;
#ifdef OLD_CODE
if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
{
std::cerr << "AuthSSLimpl::SignX509Req() rand FAIL" << std::endl;
return NULL;
}
#endif
ASN1_INTEGER *serial = ASN1_INTEGER_new();
if (!BN_to_ASN1_INTEGER(btmp, serial))
{
std::cerr << "AuthSSLimpl::SignX509Req() asn1 FAIL" << std::endl;
@ -769,21 +784,6 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
ASN1_TIME_set(X509_get_notBefore(x509), 0);
ASN1_TIME_set(X509_get_notAfter(x509), 0);
// OLD code, sets validity time of cert to be between now and some days in the future
/*
if (!X509_gmtime_adj(X509_get_notBefore(x509),0))
{
std::cerr << "AuthSSLimpl::SignX509Req() notbefore FAIL" << std::endl;
return NULL;
}
if (!X509_gmtime_adj(X509_get_notAfter(x509), (long)60*60*24*days))
{
std::cerr << "AuthSSLimpl::SignX509Req() notafter FAIL" << std::endl;
return NULL;
}
*/
if (!X509_set_subject_name(x509, X509_REQ_get_subject_name(req)))
{
std::cerr << "AuthSSLimpl::SignX509Req() sub FAIL" << std::endl;
@ -1053,11 +1053,12 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,uint32_t& diagnostic)
#endif
hashoutl=EVP_MD_size(type);
unsigned char *buf_hashout=(unsigned char *)OPENSSL_malloc((unsigned int)hashoutl);
unsigned char *buf_hashout=NULL ;
sigoutl=2048; //hashoutl; //EVP_PKEY_size(pkey);
unsigned char *buf_sigout=(unsigned char *)OPENSSL_malloc((unsigned int)sigoutl);
uint32_t certificate_version = getX509RetroshareCertificateVersion(x509) ;
#ifdef AUTHSSL_DEBUG
std::cerr << "Buffer Sizes: in: " << inl;
std::cerr << " HashOut: " << hashoutl;
@ -1065,7 +1066,8 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,uint32_t& diagnostic)
std::cerr << std::endl;
#endif
if ((buf_in == NULL) || (buf_hashout == NULL) || (buf_sigout == NULL)) {
if ((buf_in == NULL) || (buf_sigout == NULL))
{
hashoutl=0;
sigoutl=0;
fprintf(stderr, "AuthSSLimpl::AuthX509: ASN1err(ASN1_F_ASN1_SIGN,ERR_R_MALLOC_FAILURE)\n");
@ -1082,23 +1084,34 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,uint32_t& diagnostic)
i2d(data,&p);
#endif
#ifndef V07_NON_BACKWARD_COMPATIBLE_CHANGE_003
/* data in buf_in, ready to be hashed */
EVP_DigestInit_ex(ctx,type, NULL);
EVP_DigestUpdate(ctx,(unsigned char *)buf_in,inl);
if (!EVP_DigestFinal(ctx,(unsigned char *)buf_hashout, (unsigned int *)&hashoutl))
if(certificate_version < RS_CERTIFICATE_VERSION_NUMBER_07_0001)
{
hashoutl=0;
fprintf(stderr, "AuthSSLimpl::AuthX509: ASN1err(ASN1_F_ASN1_SIGN,ERR_R_EVP_LIB)\n");
diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_MALLOC_ERROR ;
goto err;
}
buf_hashout=(unsigned char *)OPENSSL_malloc((unsigned int)hashoutl);
if(buf_hashout == NULL)
{
hashoutl=0;
sigoutl=0;
fprintf(stderr, "AuthSSLimpl::AuthX509: ASN1err(ASN1_F_ASN1_SIGN,ERR_R_MALLOC_FAILURE)\n");
diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_MALLOC_ERROR ;
goto err;
}
/* data in buf_in, ready to be hashed */
EVP_DigestInit_ex(ctx,type, NULL);
EVP_DigestUpdate(ctx,(unsigned char *)buf_in,inl);
if (!EVP_DigestFinal(ctx,(unsigned char *)buf_hashout, (unsigned int *)&hashoutl))
{
hashoutl=0;
fprintf(stderr, "AuthSSLimpl::AuthX509: ASN1err(ASN1_F_ASN1_SIGN,ERR_R_EVP_LIB)\n");
diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_MALLOC_ERROR ;
goto err;
}
#ifdef AUTHSSL_DEBUG
std::cerr << "Digest Applied: len: " << hashoutl << std::endl;
#endif
std::cerr << "Digest Applied: len: " << hashoutl << std::endl;
#endif
}
/* copy data into signature */
if(sigoutl < signature->length)
@ -1180,11 +1193,17 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,uint32_t& diagnostic)
// passed, verify the signature itself
#ifdef V07_NON_BACKWARD_COMPATIBLE_CHANGE_003
if (!AuthGPG::getAuthGPG()->VerifySignBin(buf_in, inl, buf_sigout, (unsigned int) sigoutl, pd.fpr)) {
#else
if (!AuthGPG::getAuthGPG()->VerifySignBin(buf_hashout, hashoutl, buf_sigout, (unsigned int) sigoutl, pd.fpr)) {
#endif
if(certificate_version < RS_CERTIFICATE_VERSION_NUMBER_07_0001)
{
if (!AuthGPG::getAuthGPG()->VerifySignBin(buf_hashout, hashoutl, buf_sigout, (unsigned int) sigoutl, pd.fpr))
{
sigoutl = 0;
diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE ;
goto err;
}
}
else if (!AuthGPG::getAuthGPG()->VerifySignBin(buf_in, inl, buf_sigout, (unsigned int) sigoutl, pd.fpr))
{
sigoutl = 0;
diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE ;
goto err;
@ -1193,7 +1212,8 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,uint32_t& diagnostic)
RsPeerId peerIdstr ;
getX509id(x509, peerIdstr) ;
std::cerr << "Verified signature of type " << sigtypestring << " on certificate " << peerIdstr << " using PGP key with fingerprint " << pd.fpr.toStdString() << std::endl;
std::cerr << "Verified signature of type " << sigtypestring << " on certificate " << peerIdstr << " Version " << std::hex << certificate_version
<< std::dec << " using PGP key with fingerprint " << pd.fpr.toStdString() << std::endl;
}
#ifdef AUTHSSL_DEBUG

View File

@ -611,47 +611,52 @@ bool getX509id(X509 *x509, RsPeerId& xid)
X509_get0_signature(&signature,&algor,x509);
#endif
#ifdef V07_NON_BACKWARD_COMPATIBLE_CHANGE_001
// What: Computes the node id by performing a sha256 hash of the certificate's PGP signature, instead of simply picking up the last 20 bytes of it.
//
// Why: There is no real risk in forging a certificate with the same ID as the authentication is performed over the PGP signature of the certificate
// which hashes the full SSL certificate (i.e. the full serialized CERT_INFO structure). However the possibility to
// create two certificates with the same IDs is a problem, as it can be used to cause disturbance in the software.
//
// Backward compat: makes connexions impossible with non patched peers, probably because the SSL id that is computed is not the same on both side,
// and in particular unpatched peers see a cerficate with ID different (because computed with the old method) than the ID that was
// submitted when making friends.
//
// Note: the advantage of basing the ID on the signature rather than the public key is not very clear, given that the signature is based on a hash
// of the public key (and the rest of the certificate info).
//
uint32_t version_number = getX509RetroshareCertificateVersion(x509) ;
if(RsPeerId::SIZE_IN_BYTES > Sha256CheckSum::SIZE_IN_BYTES)
return false ;
xid = RsPeerId(RsDirUtil::sha256sum(ASN1_STRING_data(const_cast<ASN1_BIT_STRING*>(signature)),ASN1_STRING_length(signature)).toByteArray()) ;
#else
int signlen = ASN1_STRING_length(signature);
if (signlen < CERTSIGNLEN)
if(version_number >= RS_CERTIFICATE_VERSION_NUMBER_06_0001)
{
#ifdef AUTHSSL_DEBUG
std::cerr << "AuthSSL::getX509id() ERROR: Short Signature";
std::cerr << std::endl;
#endif
return false;
// What: Computes the node id by performing a sha256 hash of the certificate's PGP signature, instead of simply picking up the last 20 bytes of it.
//
// Why: There is no real risk in forging a certificate with the same ID as the authentication is performed over the PGP signature of the certificate
// which hashes the full SSL certificate (i.e. the full serialized CERT_INFO structure). However the possibility to
// create two certificates with the same IDs is a problem, as it can be used to cause disturbance in the software.
//
// Backward compat: makes connexions impossible with non patched peers, probably because the SSL id that is computed is not the same on both side,
// and in particular unpatched peers see a cerficate with ID different (because computed with the old method) than the ID that was
// submitted when making friends.
//
// Note: the advantage of basing the ID on the signature rather than the public key is not very clear, given that the signature is based on a hash
// of the public key (and the rest of the certificate info).
//
if(RsPeerId::SIZE_IN_BYTES > Sha256CheckSum::SIZE_IN_BYTES)
return false ;
xid = RsPeerId(RsDirUtil::sha256sum(ASN1_STRING_data(const_cast<ASN1_BIT_STRING*>(signature)),ASN1_STRING_length(signature)).toByteArray()) ;
}
else
{
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(const_cast<ASN1_BIT_STRING*>(signature));
// else copy in the first CERTSIGNLEN.
unsigned char *signdata = ASN1_STRING_data(const_cast<ASN1_BIT_STRING*>(signature));
/* switched to the other end of the signature. for
* more randomness
*/
/* switched to the other end of the signature. for
* more randomness
*/
#warning csoler 2017-02-19: This is cryptographically horrible. We should hash the entire signature here!
xid = RsPeerId(&signdata[signlen - CERTSIGNLEN]) ;
#endif
xid = RsPeerId(&signdata[signlen - CERTSIGNLEN]) ;
}
return true;
}
@ -680,6 +685,34 @@ bool CheckX509Certificate(X509 */*x509*/)
return true;
}
uint64_t getX509SerialNumber(X509 *cert)
{
ASN1_INTEGER *serial = X509_get_serialNumber(cert);
BIGNUM *btmp = ASN1_INTEGER_to_BN(serial, NULL);
uint64_t res = BN_get_word(btmp) ;
BN_free(btmp);
return res ;
}
uint32_t getX509RetroshareCertificateVersion(X509 *cert)
{
// Because the serial number was totally random before being used to identity the handshake protocol, we check if we see known version strings. If not,
// we assume v0.6-0000
//
// We compare the uint32_t into a uint64_t on purpose,to make sure that the highest bits are 0 and not random.
switch(getX509SerialNumber(cert))
{
case uint64_t(RS_CERTIFICATE_VERSION_NUMBER_06_0000): return RS_CERTIFICATE_VERSION_NUMBER_06_0000 ;
case uint64_t(RS_CERTIFICATE_VERSION_NUMBER_06_0001): return RS_CERTIFICATE_VERSION_NUMBER_06_0001 ;
case uint64_t(RS_CERTIFICATE_VERSION_NUMBER_07_0001): return RS_CERTIFICATE_VERSION_NUMBER_07_0001 ;
default:
return RS_CERTIFICATE_VERSION_NUMBER_06_0000;
}
}
// Not dependent on sslroot. load, and detroys the X509 memory.
int LoadCheckX509(const char *cert_file, RsPgpId& issuerName, std::string &location, RsPeerId &userId)

View File

@ -61,7 +61,15 @@ int EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key);
#endif
// Certificates serial number is used to store the protocol version for the handshake. (*) means current version.
//
// 06_0000: < Nov.2017.
// * 06_0001: > Nov 2017. SSL id is computed by hashing the entire signature of the cert instead of simply picking up the last bytes.
// 07_0001: Signatures are performed using SHA256+RSA instead of SHA1+RSA
static const uint32_t RS_CERTIFICATE_VERSION_NUMBER_06_0000 = 0x00060000 ; // means version RS-0.6, certificate version 0. Default version before patch.
static const uint32_t RS_CERTIFICATE_VERSION_NUMBER_06_0001 = 0x00060001 ; // means version RS-0.6, certificate version 1.
static const uint32_t RS_CERTIFICATE_VERSION_NUMBER_07_0001 = 0x00070001 ; // means version RS-0.7, certificate version 1.
X509_REQ *GenerateX509Req(
std::string pkey_file, std::string passwd,
@ -122,6 +130,9 @@ std::string getX509OrgString(X509_NAME *name);
std::string getX509CountryString(X509_NAME *name);
std::string getX509Info(X509 *cert);
uint64_t getX509SerialNumber(X509 *cert);
uint32_t getX509RetroshareCertificateVersion(X509 *cert) ;
/********** SSL ERROR STUFF ******************************************/
int printSSLError(SSL *ssl, int retval, int err, unsigned long err2, std::string &out);

View File

@ -273,7 +273,7 @@ rs_chatserver {
# which hashes the full SSL certificate (i.e. the full serialized CERT_INFO structure). However the possibility to
# create two certificates with the same IDs is a problem, as it can be used to cause disturbance in the software.
#
# Backward compat: makes connexions impossible with non patched peers, probably because the SSL id that is computed is not the same on both side,
# Backward compat: connexions impossible with non patched peers older than Nov 2017, probably because the SSL id that is computed is not the same on both side,
# and in particular unpatched peers see a cerficate with ID different (because computed with the old method) than the ID that was
# submitted when making friends.
#
@ -286,7 +286,7 @@ rs_chatserver {
#
# Why: Sha1 is likely to be prone to primary collisions anytime soon, so it is urgent to turn to a more secure solution.
#
# Backward compat: unpatched peers are able to verify signatures since openpgp-sdk already handle it.
# Backward compat: unpatched peers after Nov 2017 are able to verify signatures since openpgp-sdk already handle it.
#
# V07_NON_BACKWARD_COMPATIBLE_CHANGE_003:
#
@ -294,7 +294,7 @@ rs_chatserver {
#
# Why: hasing twice is not per se a security issue, but it makes it harder to change the settings for hashing.
#
# Backward compat: patched peers cannot connect to non patched peers.
# Backward compat: patched peers cannot connect to non patched peers older than Nov 2017.
###########################################################################################################################################################
rs_v07_changes {