- made errors of certificate (new formaT) parsing translatable.

- added checksum code for new format certificate. Will be enabled in v0.6, since it is not backward compatible
- fixed very stupid bug in radix64 cleaning function, causing any certificate to be accepted as a radix string
- added list of non backward compatible changes in README.txt, so that we can track them


git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@6030 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
csoler 2012-12-22 21:22:03 +00:00
parent 0f26b85a88
commit d893d30883
8 changed files with 114 additions and 31 deletions

View File

@ -1,4 +1,4 @@
To use this branch: To compile:
- get source code for libssh-0.5.2, unzip it, and create build directory (if needed) - get source code for libssh-0.5.2, unzip it, and create build directory (if needed)
@ -36,3 +36,8 @@ To use this branch:
and use the command line interface to control your RS instance. and use the command line interface to control your RS instance.
List of non backward compatible changes for V0.6:
================================================
- in rscertificate.cc, enable V_06_USE_CHECKSUM
- in p3charservice, remove all usage of _deprecated items

View File

@ -8,7 +8,9 @@
#include <pgp/pgpkeyutil.h> #include <pgp/pgpkeyutil.h>
#include "rscertificate.h" #include "rscertificate.h"
#define DEBUG_RSCERTIFICATE //#define DEBUG_RSCERTIFICATE
//#define V_06_USE_CHECKSUM
static const std::string PGP_CERTIFICATE_START ( "-----BEGIN PGP PUBLIC KEY BLOCK-----" ); static const std::string PGP_CERTIFICATE_START ( "-----BEGIN PGP PUBLIC KEY BLOCK-----" );
static const std::string PGP_CERTIFICATE_END ( "-----END PGP PUBLIC KEY BLOCK-----" ); static const std::string PGP_CERTIFICATE_END ( "-----END PGP PUBLIC KEY BLOCK-----" );
@ -23,10 +25,11 @@ static const uint8_t CERTIFICATE_PTAG_LOCIPANDPORT_SECTION = 0x03 ;
static const uint8_t CERTIFICATE_PTAG_DNS_SECTION = 0x04 ; static const uint8_t CERTIFICATE_PTAG_DNS_SECTION = 0x04 ;
static const uint8_t CERTIFICATE_PTAG_SSLID_SECTION = 0x05 ; static const uint8_t CERTIFICATE_PTAG_SSLID_SECTION = 0x05 ;
static const uint8_t CERTIFICATE_PTAG_NAME_SECTION = 0x06 ; static const uint8_t CERTIFICATE_PTAG_NAME_SECTION = 0x06 ;
static const uint8_t CERTIFICATE_PTAG_CHECKSUM_SECTION = 0x07 ;
static bool is_acceptable_radix64Char(char c) static bool is_acceptable_radix64Char(char c)
{ {
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '+' || c == '/' || '=' ; return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '+' || c == '/' || c == '=' ;
} }
RsCertificate::~RsCertificate() RsCertificate::~RsCertificate()
@ -80,7 +83,17 @@ std::string RsCertificate::toStdString() const
addPacket( CERTIFICATE_PTAG_NAME_SECTION , (unsigned char *)location_name.c_str() ,location_name.length() , buf, p, BS ) ; addPacket( CERTIFICATE_PTAG_NAME_SECTION , (unsigned char *)location_name.c_str() ,location_name.length() , buf, p, BS ) ;
addPacket( CERTIFICATE_PTAG_SSLID_SECTION , location_id.toByteArray() ,location_id.SIZE_IN_BYTES, buf, p, BS ) ; addPacket( CERTIFICATE_PTAG_SSLID_SECTION , location_id.toByteArray() ,location_id.SIZE_IN_BYTES, buf, p, BS ) ;
} }
#ifdef V_06_USE_CHECKSUM
uint32_t computed_crc = PGPKeyManagement::compute24bitsCRC(buf,p) ;
// handle endian issues.
unsigned char mem[3] ;
mem[0] = computed_crc & 0xff ;
mem[1] = (computed_crc >> 8 ) & 0xff ;
mem[2] = (computed_crc >> 16) & 0xff ;
addPacket( CERTIFICATE_PTAG_CHECKSUM_SECTION,mem,3,buf,p,BS) ;
#endif
std::string out_string ; std::string out_string ;
Radix64::encode((char *)buf, p, out_string) ; Radix64::encode((char *)buf, p, out_string) ;
@ -108,10 +121,10 @@ RsCertificate::RsCertificate(const std::string& str)
pgp_version("Version: OpenPGP:SDK v0.9"), pgp_version("Version: OpenPGP:SDK v0.9"),
dns_name(""),only_pgp(true) dns_name(""),only_pgp(true)
{ {
std::string err_string ; uint32_t err_code ;
if(!initFromString(str,err_string) && !initFromString_oldFormat(str,err_string)) if(!initFromString(str,err_code) && !initFromString_oldFormat(str,err_code))
throw std::runtime_error(err_string) ; throw err_code ;
} }
RsCertificate::RsCertificate(const RsPeerDetails& Detail, const unsigned char *binary_pgp_block,size_t binary_pgp_block_size) RsCertificate::RsCertificate(const RsPeerDetails& Detail, const unsigned char *binary_pgp_block,size_t binary_pgp_block_size)
@ -162,9 +175,10 @@ void RsCertificate::scan_ip(const std::string& ip_string, unsigned short port,un
ip_and_port[5] = port & 0xff ; ip_and_port[5] = port & 0xff ;
} }
bool RsCertificate::initFromString(const std::string& instr,std::string& err_string) bool RsCertificate::initFromString(const std::string& instr,uint32_t& err_code)
{ {
std::string str ; std::string str ;
err_code = CERTIFICATE_PARSING_ERROR_NO_ERROR ;
// 0 - clean the string and check that it is pure radix64 // 0 - clean the string and check that it is pure radix64
// //
@ -179,7 +193,7 @@ bool RsCertificate::initFromString(const std::string& instr,std::string& err_str
str += instr[i] ; str += instr[i] ;
} }
#ifdef DEBUG_RSCERTIFICATE #ifdef DEBUG_RSCERTIFICATE
std::cerr << "Decodign from:" << str << std::endl; std::cerr << "Decoding from:" << str << std::endl;
#endif #endif
// 1 - decode the string. // 1 - decode the string.
// //
@ -187,6 +201,7 @@ bool RsCertificate::initFromString(const std::string& instr,std::string& err_str
size_t size ; size_t size ;
Radix64::decode(str,bf, size) ; Radix64::decode(str,bf, size) ;
bool checksum_check_passed = false ;
unsigned char *buf = (unsigned char *)bf ; unsigned char *buf = (unsigned char *)bf ;
size_t total_s = 0 ; size_t total_s = 0 ;
only_pgp = true ; only_pgp = true ;
@ -203,7 +218,7 @@ bool RsCertificate::initFromString(const std::string& instr,std::string& err_str
if(total_s > size) if(total_s > size)
{ {
err_string = "Abnormal size read. Bigger than memory block." ; err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR ;
return false ; return false ;
} }
@ -225,7 +240,7 @@ bool RsCertificate::initFromString(const std::string& instr,std::string& err_str
case CERTIFICATE_PTAG_SSLID_SECTION: case CERTIFICATE_PTAG_SSLID_SECTION:
if(s != location_id.SIZE_IN_BYTES) if(s != location_id.SIZE_IN_BYTES)
{ {
err_string = "Inconsistent size in certificate section 'location ID'" ; err_code = CERTIFICATE_PARSING_ERROR_INVALID_LOCATION_ID ;
return false ; return false ;
} }
@ -241,7 +256,7 @@ bool RsCertificate::initFromString(const std::string& instr,std::string& err_str
case CERTIFICATE_PTAG_LOCIPANDPORT_SECTION: case CERTIFICATE_PTAG_LOCIPANDPORT_SECTION:
if(s != 6) if(s != 6)
{ {
err_string = "Inconsistent size in certificate section 'external IP'" ; err_code = CERTIFICATE_PARSING_ERROR_INVALID_LOCAL_IP;
return false ; return false ;
} }
@ -251,20 +266,49 @@ bool RsCertificate::initFromString(const std::string& instr,std::string& err_str
case CERTIFICATE_PTAG_EXTIPANDPORT_SECTION: case CERTIFICATE_PTAG_EXTIPANDPORT_SECTION:
if(s != 6) if(s != 6)
{ {
err_string = "Inconsistent size in certificate section 'external IP'" ; err_code = CERTIFICATE_PARSING_ERROR_INVALID_EXTERNAL_IP;
return false ; return false ;
} }
memcpy(ipv4_external_ip_and_port,buf,s) ; memcpy(ipv4_external_ip_and_port,buf,s) ;
buf = &buf[s] ; buf = &buf[s] ;
break ; break ;
case CERTIFICATE_PTAG_CHECKSUM_SECTION:
{
if(s != 3 || total_s+3 != size)
{
err_code = CERTIFICATE_PARSING_ERROR_INVALID_CHECKSUM_SECTION ;
return false ;
}
uint32_t computed_crc = PGPKeyManagement::compute24bitsCRC((unsigned char *)bf,size-5) ;
uint32_t certificate_crc = buf[0] + (buf[1] << 8) + (buf[2] << 16) ;
if(computed_crc != certificate_crc)
{
err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR ;
return false ;
}
else
checksum_check_passed = true ;
}
break ;
default: default:
err_string = "Cannot read certificate. Parsing error in binary packets." ; err_code = CERTIFICATE_PARSING_ERROR_UNKNOWN_SECTION_PTAG ;
return false ; return false ;
} }
total_s += s ; total_s += s ;
} }
#ifdef V_06_USE_CHECKSUM
if(!checksum_check_passed)
{
err_code = CERTIFICATE_PARSING_ERROR_MISSING_CHECKSUM ;
return false ;
}
#endif
if(total_s != size)
std::cerr << "(EE) Certificate contains trailing characters. Weird." << std::endl;
delete[] bf ; delete[] bf ;
return true ; return true ;
@ -755,7 +799,7 @@ std::string RsCertificate::toStdString_oldFormat() const
return res ; return res ;
} }
bool RsCertificate::initFromString_oldFormat(const std::string& certstr,std::string& err_string) bool RsCertificate::initFromString_oldFormat(const std::string& certstr,uint32_t& err_code)
{ {
//parse the text to get ip address //parse the text to get ip address
try try

View File

@ -51,8 +51,8 @@ class RsCertificate
static bool cleanCertificate_oldFormat(const std::string& input,std::string& output,int&) ; // old text format static bool cleanCertificate_oldFormat(const std::string& input,std::string& output,int&) ; // old text format
static void scan_ip(const std::string& ip_string, unsigned short port,unsigned char *destination_memory) ; static void scan_ip(const std::string& ip_string, unsigned short port,unsigned char *destination_memory) ;
bool initFromString(const std::string& str,std::string& err_string) ; bool initFromString(const std::string& str,uint32_t& err_code) ;
bool initFromString_oldFormat(const std::string& str,std::string& err_string) ; bool initFromString_oldFormat(const std::string& str,uint32_t& err_code) ;
static void addPacket(uint8_t ptag, const unsigned char *mem, size_t size, unsigned char *& buf, size_t& offset, size_t& buf_size) ; static void addPacket(uint8_t ptag, const unsigned char *mem, size_t size, unsigned char *& buf, size_t& offset, size_t& buf_size) ;

View File

@ -83,7 +83,8 @@ const uint32_t RS_PEER_CONNECTSTATE_CONNECTED_UDP = 5;
const uint32_t RS_PEER_CONNECTSTATE_CONNECTED_TUNNEL = 6; const uint32_t RS_PEER_CONNECTSTATE_CONNECTED_TUNNEL = 6;
const uint32_t RS_PEER_CONNECTSTATE_CONNECTED_UNKNOWN = 7; const uint32_t RS_PEER_CONNECTSTATE_CONNECTED_UNKNOWN = 7;
/* Error codes for certificate cleaning */ /* Error codes for certificate cleaning and cert parsing. Numbers should not overlap. */
const int RS_PEER_CERT_CLEANING_CODE_NO_ERROR = 0x00 ; const int RS_PEER_CERT_CLEANING_CODE_NO_ERROR = 0x00 ;
const int RS_PEER_CERT_CLEANING_CODE_UNKOWN_ERROR = 0x01 ; const int RS_PEER_CERT_CLEANING_CODE_UNKOWN_ERROR = 0x01 ;
const int RS_PEER_CERT_CLEANING_CODE_NO_BEGIN_TAG = 0x02 ; const int RS_PEER_CERT_CLEANING_CODE_NO_BEGIN_TAG = 0x02 ;
@ -92,6 +93,16 @@ const int RS_PEER_CERT_CLEANING_CODE_NO_CHECKSUM = 0x04 ;
const int RS_PEER_CERT_CLEANING_CODE_WRONG_NUMBER = 0x05 ; const int RS_PEER_CERT_CLEANING_CODE_WRONG_NUMBER = 0x05 ;
const int RS_PEER_CERT_CLEANING_CODE_WRONG_RADIX_CHAR = 0x06 ; const int RS_PEER_CERT_CLEANING_CODE_WRONG_RADIX_CHAR = 0x06 ;
const uint32_t CERTIFICATE_PARSING_ERROR_NO_ERROR = 0x10 ;
const uint32_t CERTIFICATE_PARSING_ERROR_SIZE_ERROR = 0x11 ;
const uint32_t CERTIFICATE_PARSING_ERROR_INVALID_LOCATION_ID = 0x12 ;
const uint32_t CERTIFICATE_PARSING_ERROR_INVALID_EXTERNAL_IP = 0x13 ;
const uint32_t CERTIFICATE_PARSING_ERROR_INVALID_LOCAL_IP = 0x14 ;
const uint32_t CERTIFICATE_PARSING_ERROR_INVALID_CHECKSUM_SECTION = 0x15 ;
const uint32_t CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR = 0x16 ;
const uint32_t CERTIFICATE_PARSING_ERROR_UNKNOWN_SECTION_PTAG = 0x17 ;
const uint32_t CERTIFICATE_PARSING_ERROR_MISSING_CHECKSUM = 0x18 ;
/* LinkType Flags */ /* LinkType Flags */
// CONNECTION // CONNECTION
@ -131,6 +142,7 @@ const uint32_t RS_NET_CONN_TYPE_FRIEND = 0x02000000;
const uint32_t RS_NET_CONN_TYPE_SERVER = 0x04000000; const uint32_t RS_NET_CONN_TYPE_SERVER = 0x04000000;
const uint32_t RS_NET_CONN_TYPE_CLIENT = 0x08000000; const uint32_t RS_NET_CONN_TYPE_CLIENT = 0x08000000;
// Potential certificate parsing errors.
/* Groups */ /* Groups */
@ -288,7 +300,7 @@ class RsPeers
virtual bool loadCertificateFromString(const std::string &cert, std::string &ssl_id, std::string &gpg_id) = 0; virtual bool loadCertificateFromString(const std::string &cert, std::string &ssl_id, std::string &gpg_id) = 0;
// Gets the GPG details, but does not add the key to the keyring. // Gets the GPG details, but does not add the key to the keyring.
virtual bool loadDetailsFromStringCert(const std::string& certGPG, RsPeerDetails &pd,std::string& error_string) = 0; virtual bool loadDetailsFromStringCert(const std::string& certGPG, RsPeerDetails &pd,uint32_t& error_code) = 0;
virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert,int& error_code) = 0; virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert,int& error_code) = 0;
virtual bool saveCertificateToFile(const std::string &id, const std::string &fname) = 0; virtual bool saveCertificateToFile(const std::string &id, const std::string &fname) = 0;

View File

@ -905,7 +905,7 @@ bool p3Peers::loadCertificateFromFile(const std::string &/*fname*/, std::string
return false; return false;
} }
bool p3Peers::loadDetailsFromStringCert(const std::string &certstr, RsPeerDetails &pd,std::string& /*error_string*/) bool p3Peers::loadDetailsFromStringCert(const std::string &certstr, RsPeerDetails &pd,uint32_t& error_code)
{ {
#ifdef P3PEERS_DEBUG #ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::LoadCertificateFromString() "; std::cerr << "p3Peers::LoadCertificateFromString() ";
@ -932,9 +932,10 @@ bool p3Peers::loadDetailsFromStringCert(const std::string &certstr, RsPeerDetai
pd.isOnlyGPGdetail = pd.id.empty(); pd.isOnlyGPGdetail = pd.id.empty();
pd.service_perm_flags = RS_SERVICE_PERM_ALL ; pd.service_perm_flags = RS_SERVICE_PERM_ALL ;
} }
catch (...) catch(uint32_t e)
{ {
std::cerr << "ConnectFriendWizard : Parse ip address error." << std::endl; std::cerr << "ConnectFriendWizard : Parse ip address error :" << e << std::endl;
error_code = e;
return false ; return false ;
} }

View File

@ -103,7 +103,7 @@ virtual bool hasExportMinimal() ;
virtual bool loadCertificateFromFile(const std::string &fname, std::string &id, std::string &gpg_id); virtual bool loadCertificateFromFile(const std::string &fname, std::string &id, std::string &gpg_id);
virtual bool loadCertificateFromString(const std::string& cert, std::string &id, std::string &gpg_id); virtual bool loadCertificateFromString(const std::string& cert, std::string &id, std::string &gpg_id);
virtual bool loadDetailsFromStringCert(const std::string &cert, RsPeerDetails &pd, std::string& error_string); virtual bool loadDetailsFromStringCert(const std::string &cert, RsPeerDetails &pd, uint32_t& error_code);
virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert,int& error_code); virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert,int& error_code);
virtual bool saveCertificateToFile(const std::string &id, const std::string &fname); virtual bool saveCertificateToFile(const std::string &id, const std::string &fname);

View File

@ -96,6 +96,24 @@ ConnectFriendWizard::ConnectFriendWizard(QWidget *parent) :
ui->rsidRadioButton->hide(); ui->rsidRadioButton->hide();
} }
QString ConnectFriendWizard::getErrorString(uint32_t error_code)
{
switch(error_code)
{
case CERTIFICATE_PARSING_ERROR_SIZE_ERROR: return tr("Abnormal size read is bigger than memory block.") ;
case CERTIFICATE_PARSING_ERROR_INVALID_LOCATION_ID: return tr("Invalid location id.") ;
case CERTIFICATE_PARSING_ERROR_INVALID_EXTERNAL_IP: return tr("Invalid external IP.") ;
case CERTIFICATE_PARSING_ERROR_INVALID_LOCAL_IP: return tr("Invalid local IP.") ;
case CERTIFICATE_PARSING_ERROR_INVALID_CHECKSUM_SECTION: return tr("Invalid checksum section.") ;
case CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR: return tr("Checksum mismatch. Certificate is corrupted.") ;
case CERTIFICATE_PARSING_ERROR_UNKNOWN_SECTION_PTAG: return tr("Unknown section type found (Certificate might be corrupted).") ;
case CERTIFICATE_PARSING_ERROR_MISSING_CHECKSUM: return tr("Missing checksum.") ;
default:
return tr("Unknown certificate error") ;
}
}
void ConnectFriendWizard::setCertificate(const QString &certificate, bool friendRequest) void ConnectFriendWizard::setCertificate(const QString &certificate, bool friendRequest)
{ {
if (certificate.isEmpty()) { if (certificate.isEmpty()) {
@ -103,9 +121,9 @@ void ConnectFriendWizard::setCertificate(const QString &certificate, bool friend
return; return;
} }
std::string error_string; uint32_t cert_load_error_code;
if (rsPeers->loadDetailsFromStringCert(certificate.toUtf8().constData(), peerDetails, error_string)) if (rsPeers->loadDetailsFromStringCert(certificate.toUtf8().constData(), peerDetails, cert_load_error_code))
{ {
#ifdef FRIEND_WIZARD_DEBUG #ifdef FRIEND_WIZARD_DEBUG
std::cerr << "ConnectFriendWizard got id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl; std::cerr << "ConnectFriendWizard got id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl;
@ -114,7 +132,7 @@ void ConnectFriendWizard::setCertificate(const QString &certificate, bool friend
setStartId(friendRequest ? Page_FriendRequest : Page_Conclusion); setStartId(friendRequest ? Page_FriendRequest : Page_Conclusion);
} else { } else {
// error message // error message
setField("errorMessage", tr("Certificate Load Failed") + ": " + QString::fromUtf8(error_string.c_str())); setField("errorMessage", tr("Certificate Load Failed") + ": \n\n" + getErrorString(cert_load_error_code)) ;
setStartId(Page_ErrorMessage); setStartId(Page_ErrorMessage);
} }
} }
@ -372,9 +390,9 @@ bool ConnectFriendWizard::validateCurrentPage()
case Page_Text: case Page_Text:
{ {
std::string certstr = ui->friendCertEdit->toPlainText().toUtf8().constData(); std::string certstr = ui->friendCertEdit->toPlainText().toUtf8().constData();
std::string error_string; uint32_t cert_load_error_code;
if (rsPeers->loadDetailsFromStringCert(certstr, peerDetails, error_string)) { if (rsPeers->loadDetailsFromStringCert(certstr, peerDetails, cert_load_error_code)) {
mCertificate = certstr; mCertificate = certstr;
#ifdef FRIEND_WIZARD_DEBUG #ifdef FRIEND_WIZARD_DEBUG
std::cerr << "ConnectFriendWizard got id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl; std::cerr << "ConnectFriendWizard got id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl;
@ -382,7 +400,7 @@ bool ConnectFriendWizard::validateCurrentPage()
break; break;
} }
// error message // error message
setField("errorMessage", tr("Certificate Load Failed") + ": " + QString::fromUtf8(error_string.c_str())); setField("errorMessage", tr("Certificate Load Failed") + ": \n\n" + getErrorString(cert_load_error_code)) ;
error = false; error = false;
break; break;
} }
@ -406,14 +424,14 @@ bool ConnectFriendWizard::validateCurrentPage()
break; break;
} }
std::string error_string; uint32_t cert_error_code;
if (rsPeers->loadDetailsFromStringCert(certstr, peerDetails, error_string)) { if (rsPeers->loadDetailsFromStringCert(certstr, peerDetails, cert_error_code)) {
mCertificate = certstr; mCertificate = certstr;
#ifdef FRIEND_WIZARD_DEBUG #ifdef FRIEND_WIZARD_DEBUG
std::cerr << "ConnectFriendWizard got id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl; std::cerr << "ConnectFriendWizard got id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl;
#endif #endif
} else { } else {
setField("errorMessage", QString(tr("Certificate Load Failed:something is wrong with %1 ")).arg(fn) + ": " + QString::fromUtf8(error_string.c_str())); setField("errorMessage", QString(tr("Certificate Load Failed:something is wrong with %1 ")).arg(fn) + ": " + getErrorString(cert_error_code));
error = false; error = false;
} }
} else { } else {

View File

@ -68,6 +68,9 @@ private slots:
void groupCurrentIndexChanged(int index); void groupCurrentIndexChanged(int index);
private: private:
// returns the translated error string for the error code (to be found in rspeers.h)
QString getErrorString(uint32_t) ;
bool error; bool error;
RsPeerDetails peerDetails; RsPeerDetails peerDetails;
std::string mCertificate; std::string mCertificate;