#include #include #include #include #include #include #include #include "rscertificate.h" #define DEBUG_RSCERTIFICATE 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 EXTERNAL_IP_BEGIN_SECTION ( "--EXT--" ); static const std::string LOCAL_IP_BEGIN_SECTION ( "--LOCAL--" ); static const std::string SSLID_BEGIN_SECTION ( "--SSLID--" ); static const std::string LOCATION_BEGIN_SECTION ( "--LOCATION--" ); static const uint8_t CERTIFICATE_PTAG_PGP_SECTION = 0x01 ; static const uint8_t CERTIFICATE_PTAG_EXTIPANDPORT_SECTION = 0x02 ; static const uint8_t CERTIFICATE_PTAG_LOCIPANDPORT_SECTION = 0x03 ; static const uint8_t CERTIFICATE_PTAG_DNS_SECTION = 0x04 ; static const uint8_t CERTIFICATE_PTAG_SSLID_SECTION = 0x05 ; static const uint8_t CERTIFICATE_PTAG_NAME_SECTION = 0x06 ; static bool is_acceptable_radix64Char(char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '+' || c == '/' || '=' ; } RsCertificate::~RsCertificate() { delete[] binary_pgp_key ; } void RsCertificate::addPacket(uint8_t ptag, const unsigned char *mem, size_t size, unsigned char *& buf, size_t& offset, size_t& buf_size) { // Check that the buffer has sufficient size. If not, increase it. while(offset + size + 6 >= buf_size) { unsigned char *newbuf = new unsigned char[2*buf_size] ; memcpy(newbuf, buf, buf_size) ; buf_size *= 2 ; delete[] buf ; buf = newbuf ; } // Write ptag and size buf[offset] = ptag ; offset += 1 ; offset += PGPKeyParser::write_125Size(&buf[offset],size) ; // Copy the data memcpy(&buf[offset], mem, size) ; offset += size ; } std::string RsCertificate::toStdString() const { std::string res ; size_t BS = 1000 ; size_t p = 0 ; unsigned char *buf = new unsigned char[BS] ; addPacket( CERTIFICATE_PTAG_PGP_SECTION , binary_pgp_key , binary_pgp_key_size , buf, p, BS ) ; addPacket( CERTIFICATE_PTAG_EXTIPANDPORT_SECTION, ipv4_external_ip_and_port , 6 , buf, p, BS ) ; addPacket( CERTIFICATE_PTAG_LOCIPANDPORT_SECTION, ipv4_internal_ip_and_port , 6 , buf, p, BS ) ; addPacket( CERTIFICATE_PTAG_DNS_SECTION , (unsigned char *)dns_name.c_str() , dns_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 ) ; std::string out_string ; Radix64::encode((char *)buf, p, out_string) ; // Now slice up to 64 chars. // std::string out2 ; static const int LINE_LENGTH = 64 ; for(int i=0;i<(int)out_string.length();++i) { out2 += out_string[i] ; if(i % LINE_LENGTH == LINE_LENGTH-1) out2 += '\n' ; } delete[] buf ; return out2 ; } RsCertificate::RsCertificate(const std::string& str) : location_name(""), pgp_version("Version: OpenPGP:SDK v0.9"), dns_name("") { std::string err_string ; if(!initFromString(str,err_string) && !initFromString_oldFormat(str,err_string)) throw std::runtime_error(err_string) ; } RsCertificate::RsCertificate(const RsPeerDetails& Detail, const unsigned char *binary_pgp_block,size_t binary_pgp_block_size) :pgp_version("Version: OpenPGP:SDK v0.9") { if(binary_pgp_block_size == 0 || binary_pgp_block == NULL) throw std::runtime_error("Cannot init a certificate with a void key block.") ; if(Detail.isOnlyGPGdetail) throw std::runtime_error("Cannot init a certificate with a RsPeerDetails with only GPG details.") ; binary_pgp_key = new unsigned char[binary_pgp_block_size] ; memcpy(binary_pgp_key,binary_pgp_block,binary_pgp_block_size) ; binary_pgp_key_size = binary_pgp_block_size ; location_id = SSLIdType( Detail.id ) ; location_name = Detail.location ; scan_ip(Detail.localAddr,Detail.localPort,ipv4_internal_ip_and_port) ; scan_ip(Detail.extAddr,Detail.extPort,ipv4_external_ip_and_port) ; dns_name = Detail.dyndns ; } void RsCertificate::scan_ip(const std::string& ip_string, unsigned short port,unsigned char *ip_and_port) { int d0,d1,d2,d3 ; if(4 != sscanf(ip_string.c_str(),"%d.%d.%d.%d",&d0,&d1,&d2,&d3)) throw std::runtime_error( "Cannot parse ip from given string." ); ip_and_port[0] = d0 ; ip_and_port[1] = d1 ; ip_and_port[2] = d2 ; ip_and_port[3] = d3 ; ip_and_port[4] = (port >> 8 ) & 0xff ; ip_and_port[5] = port & 0xff ; } bool RsCertificate::initFromString(const std::string& instr,std::string& err_string) { std::string str ; // 0 - clean the string and check that it is pure radix64 // for(uint32_t i=0;i size) { err_string = "Abnormal size read. Bigger than memory block." ; return false ; } #ifdef DEBUG_RSCERTIFICATE std::cerr << "Packet parse: read ptag " << (int)ptag << ", size " << s << ", total_s = " << total_s << ", expected total = " << size << std::endl; #endif switch(ptag) { case CERTIFICATE_PTAG_PGP_SECTION: binary_pgp_key = new unsigned char[s] ; memcpy(binary_pgp_key,buf,s) ; binary_pgp_key_size = s ; buf = &buf[s] ; break ; case CERTIFICATE_PTAG_NAME_SECTION: location_name = std::string((char *)buf,s) ; buf = &buf[s] ; break ; case CERTIFICATE_PTAG_SSLID_SECTION: if(s != location_id.SIZE_IN_BYTES) { err_string = "Inconsistent size in certificate section 'location ID'" ; return false ; } location_id = SSLIdType(buf) ; buf = &buf[s] ; break ; case CERTIFICATE_PTAG_DNS_SECTION: dns_name = std::string((char *)buf,s) ; buf = &buf[s] ; break ; case CERTIFICATE_PTAG_LOCIPANDPORT_SECTION: if(s != 6) { err_string = "Inconsistent size in certificate section 'external IP'" ; return false ; } memcpy(ipv4_internal_ip_and_port,buf,s) ; buf = &buf[s] ; break ; case CERTIFICATE_PTAG_EXTIPANDPORT_SECTION: if(s != 6) { err_string = "Inconsistent size in certificate section 'external IP'" ; return false ; } memcpy(ipv4_external_ip_and_port,buf,s) ; buf = &buf[s] ; break ; default: err_string = "Cannot read certificate. Parsing error in binary packets." ; return false ; } total_s += s ; } delete[] bf ; return true ; } std::string RsCertificate::ext_ip_string() const { std::ostringstream os ; os << (int)ipv4_external_ip_and_port[0] << "." << (int)ipv4_external_ip_and_port[1] << "." << (int)ipv4_external_ip_and_port[2] << "." << (int)ipv4_external_ip_and_port[3] ; return os.str() ; } std::string RsCertificate::loc_ip_string() const { std::ostringstream os ; os << (int)ipv4_internal_ip_and_port[0] << "." << (int)ipv4_internal_ip_and_port[1] << "." << (int)ipv4_internal_ip_and_port[2] << "." << (int)ipv4_internal_ip_and_port[3] ; return os.str() ; } unsigned short RsCertificate::ext_port_us() const { return (int)ipv4_external_ip_and_port[4]*256 + (int)ipv4_external_ip_and_port[5] ; } unsigned short RsCertificate::loc_port_us() const { return (int)ipv4_internal_ip_and_port[4]*256 + (int)ipv4_internal_ip_and_port[5] ; } bool RsCertificate::cleanCertificate(const std::string& input,std::string& output,Format& format,int& error_code) { if(cleanCertificate_oldFormat(input,output,error_code)) { format = RS_CERTIFICATE_OLD_FORMAT ; return true ; } if(cleanCertificate(input,output,error_code)) { format = RS_CERTIFICATE_RADIX ; return true ; } return false ; } std::string RsCertificate::armouredPGPKey() const { return PGPKeyManagement::makeArmouredKey(binary_pgp_key,binary_pgp_key_size,pgp_version) ; } // Yeah, this is simple, and that is what's good about the radix format. Can't be broken ;-) // bool RsCertificate::cleanCertificate(const std::string& instr,std::string& str,int& error_code) { error_code = RS_PEER_CERT_CLEANING_CODE_NO_ERROR ; // 0 - clean the string and check that it is pure radix64 // for(uint32_t i=0;i tag"< tag"< tag"<=lengthOfCert) { std::cerr<<"Certificate corrupted beyond repair: No <------END > tag"< header; header.push_back("Version"); header.push_back("Comment"); header.push_back("MessageID"); header.push_back("Hash"); header.push_back("Charset"); for (std::list::iterator headerIt = header.begin (); headerIt != header.end(); headerIt++) { if (badCertificate.substr(currBadCertIdx, (*headerIt).length()) == *headerIt) { cleanCertificate += badCertificate.substr(currBadCertIdx, (*headerIt).length()); currBadCertIdx += (*headerIt).length(); while(currBadCertIdx=endCertStartIdx1) { std::cerr<<"Certificate corrupted beyond repair: No checksum, or no newline after first tag"<