mirror of
https://github.com/outbackdingo/sysadm.git
synced 2026-01-27 10:20:26 +00:00
Get the server all setup for enabling encryption (alternate API calls implemented - just no encryption turned on yet).
This commit is contained in:
@@ -110,6 +110,7 @@ void BridgeConnection::InjectMessage(QString msg){
|
||||
//Add the "from" ID to the message
|
||||
msg = msg.replace(0,lb,SockID); //replace the "to" ID with the "from" ID
|
||||
emit SocketMessage(toID, msg); //forward the message on to the "to" connection
|
||||
//qDebug() << "Message:" << toID << SockID << msg; //simple message snooping on the bridge - to verify server/client encryption
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,13 +338,143 @@ QString AuthorizationManager::LoginUC(QHostAddress host, QString encstring){
|
||||
}
|
||||
}
|
||||
|
||||
QString AuthorizationManager::encryptString(QString msg, QString key){
|
||||
//do nothing yet
|
||||
return msg;
|
||||
QString AuthorizationManager::encryptString(QString str, QByteArray key){
|
||||
return str; //TEMPORARY BYPASS
|
||||
bool pub=true;
|
||||
if(key.contains("--BEGIN PUBLIC KEY--")){ pub=true; }
|
||||
else if(key.contains(" PRIVATE KEY--")){ pub=false; }
|
||||
else{ return str; } //unknown encryption - just return as-is
|
||||
qDebug() << "Encrypt String:" << str << pub;//<< key;
|
||||
//Reset/Load some SSL stuff
|
||||
//OpenSSL_add_all_algorithms();
|
||||
//ERR_load_crypto_strings();
|
||||
|
||||
//Now Encrypt the string
|
||||
//qDebug() << "allocate encode array";
|
||||
unsigned char *encode = (unsigned char*)malloc(2*str.length()); //give it plenty of extra space as needed
|
||||
RSA *rsa= NULL;
|
||||
BIO *keybio = NULL;
|
||||
//qDebug() << "allocate keybio buffer";
|
||||
keybio = BIO_new_mem_buf(key.data(), -1);
|
||||
if(keybio==NULL){ return ""; }
|
||||
|
||||
if(!pub){
|
||||
//Using PRIVATE key to encrypt
|
||||
//qDebug() << "Read private key";
|
||||
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa,NULL, NULL);
|
||||
if(rsa==NULL){ return ""; }
|
||||
//qDebug() << "Encrypt with private key";
|
||||
int len = RSA_private_encrypt(str.length(), (unsigned char*)(str.toLocal8Bit().data()), encode, rsa, RSA_PKCS1_PADDING);
|
||||
if(len <0){ return ""; }
|
||||
//qDebug() << "Return base-64 encoded version";
|
||||
QByteArray str_encode( (char*)(encode), len);
|
||||
str_encode = str_encode.toBase64();
|
||||
return QString( str_encode );
|
||||
}else{
|
||||
//Using PUBLIC key to encrypt
|
||||
//qDebug() << "Read Public Key";
|
||||
rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL);
|
||||
if(rsa==NULL){ return ""; }
|
||||
//qDebug() << "Encrypt with public key";
|
||||
int len = RSA_public_encrypt(str.length(), (unsigned char*)(str.toLocal8Bit().data()), encode, rsa, RSA_PKCS1_PADDING);
|
||||
if(len <0){ return ""; }
|
||||
//qDebug() << "Return base-64 encoded version";
|
||||
QByteArray str_encode = QByteArray::fromRawData( (char*)(encode), len);
|
||||
qDebug() << "Encoded:" << str_encode;
|
||||
str_encode = str_encode.toBase64();
|
||||
qDebug() << "Could reverse encoding:" << (decryptString(str_encode, key) == str);
|
||||
qDebug() << "Base64:" << str_encode;
|
||||
|
||||
return QString( str_encode );
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
QString AuthorizationManager::decryptString(QString msg, QString key){
|
||||
return msg; //do nothing yet
|
||||
QString AuthorizationManager::decryptString(QString str, QByteArray key){
|
||||
return str; //TEMPORARY BYPASS
|
||||
bool pub=true;
|
||||
if(key.contains("--BEGIN PUBLIC KEY--")){ pub=true; }
|
||||
else if(key.contains(" PRIVATE KEY--")){ pub=false; }
|
||||
else{ return str; } //unknown encryption - just return as-is
|
||||
//Reset/Load some SSL stuff
|
||||
// OpenSSL_add_all_algorithms();
|
||||
// ERR_load_crypto_strings();
|
||||
|
||||
//Turn the encrypted string into a byte array
|
||||
QByteArray enc; enc.append(str.toLocal8Bit());
|
||||
|
||||
unsigned char *decode = (unsigned char*)malloc(2*str.length());
|
||||
RSA *rsa= NULL;
|
||||
BIO *keybio = NULL;
|
||||
//qDebug() << " - Generate keybio";
|
||||
keybio = BIO_new_mem_buf(key.data(), -1);
|
||||
if(keybio==NULL){ return ""; }
|
||||
//qDebug() << " - Read pubkey";
|
||||
if(pub){
|
||||
//PUBLIC KEY
|
||||
rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL);
|
||||
if(rsa==NULL){ qDebug() << " - Invalid RSA key!!"; return ""; }
|
||||
//qDebug() << " - Decrypt string";
|
||||
int len = RSA_public_decrypt(enc.length(), (unsigned char*)(enc.data()), decode, rsa, RSA_PKCS1_PADDING);
|
||||
if(len<0){ return ""; }
|
||||
return QString( QByteArray( (char*)(decode), len) );
|
||||
}else{
|
||||
//PRIVATE KEY
|
||||
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa,NULL, NULL);
|
||||
if(rsa==NULL){ qDebug() << " - Invalid RSA key!!"; return ""; }
|
||||
//qDebug() << " - Decrypt string";
|
||||
int len = RSA_private_decrypt(enc.length(), (unsigned char*)(enc.data()), decode, rsa, RSA_PKCS1_PADDING);
|
||||
if(len<0){ return ""; }
|
||||
return QString( QByteArray( (char*)(decode), len) );
|
||||
}
|
||||
}
|
||||
|
||||
//Additional SSL Encryption functions
|
||||
QByteArray AuthorizationManager::GenerateSSLPrivkey(){
|
||||
const int kBits = 4096; //25165824; // 3MB in bits
|
||||
const int kExp = 3;
|
||||
|
||||
int keylen;
|
||||
char *pem_key;
|
||||
|
||||
RSA *rsa = RSA_generate_key(kBits, kExp, 0, 0);
|
||||
|
||||
/* To get the C-string PEM form: */
|
||||
BIO *bio = BIO_new(BIO_s_mem());
|
||||
PEM_write_bio_RSAPrivateKey(bio, rsa, NULL, NULL, 0, NULL, NULL);
|
||||
|
||||
keylen = BIO_pending(bio);
|
||||
pem_key = (char *)malloc(keylen+1); /* Null-terminate */
|
||||
BIO_read(bio, pem_key, keylen);
|
||||
QByteArray data = QByteArray::fromRawData(pem_key, keylen);
|
||||
qDebug() << "New Priv Key:" << data;
|
||||
return data;
|
||||
}
|
||||
|
||||
QByteArray AuthorizationManager::pubkeyForMd5(QString md5_base64){
|
||||
QByteArray md5 = QByteArray::fromBase64( md5_base64.toLocal8Bit() );
|
||||
|
||||
QStringList keys; //Format: "RegisteredCerts/<user>/<key>" (value is full text)
|
||||
//Read all user's certs (since we only need checksums)
|
||||
keys = CONFIG->allKeys().filter("RegisteredCerts/");
|
||||
keys.sort();
|
||||
QJsonArray arr;
|
||||
QCryptographicHash chash(QCryptographicHash::Md5);
|
||||
//qDebug() << "MD5 Generation:";
|
||||
for(int i=0; i<keys.length(); i++){
|
||||
//qDebug() << "User:" << keys[i].section("/",1,1);
|
||||
QByteArray key = QByteArray::fromBase64( keys[i].section("/",2,-1).toLocal8Bit() ); //remember that the keys are stored internally as base64-encoded strings
|
||||
//qDebug() << " - Key:" << key;
|
||||
chash.addData( key );
|
||||
QByteArray res = chash.result();
|
||||
//qDebug() << " - md5:" << res;
|
||||
chash.reset();
|
||||
if(res==md5){
|
||||
//qDebug() << "Found key for MD5:" << key;
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return ""; //fallback - no matching key found
|
||||
}
|
||||
|
||||
// =========================
|
||||
|
||||
@@ -40,9 +40,13 @@ public:
|
||||
QString LoginUC(QHostAddress host, QString encstring);
|
||||
|
||||
//Message Encryption/decryption methods
|
||||
QString encryptString(QString msg, QString key);
|
||||
QString decryptString(QString msg, QString key);
|
||||
QString encryptString(QString msg, QByteArray key);
|
||||
QString decryptString(QString msg, QByteArray key);
|
||||
|
||||
//Additional SSL Encryption functions
|
||||
QByteArray GenerateSSLPrivkey();
|
||||
QByteArray pubkeyForMd5(QString md5_base64);
|
||||
|
||||
private:
|
||||
QHash<QString, QDateTime> HASH;
|
||||
QHash <QString, QDateTime> IPFAIL;
|
||||
|
||||
@@ -40,7 +40,7 @@ bool WebServer::startServer(quint16 port, bool websocket){
|
||||
if(ok){
|
||||
QCoreApplication::processEvents();
|
||||
qDebug() << "Server Started:" << QDateTime::currentDateTime().toString(Qt::ISODate);
|
||||
qDebug() << " Port:" << port;
|
||||
qDebug() << " Port:" << (BRIDGE_ONLY ? "(Bridge Only)" : QString::number(port));
|
||||
if(WSServer!=0){ qDebug() << " URL:" << WSServer->serverUrl().toString(); }
|
||||
}else{
|
||||
qCritical() << "Could not start server - exiting...";
|
||||
|
||||
@@ -76,7 +76,7 @@ WebSocket::WebSocket(QObject *parent, QString url, QString ID, AuthorizationMana
|
||||
TSOCKET = 0;
|
||||
AUTHSYSTEM = auth;
|
||||
SockPeerIP = SOCKET->peerAddress().toString();
|
||||
LogManager::log(LogManager::HOST,"New Connection: "+SockPeerIP);
|
||||
//LogManager::log(LogManager::HOST,"New Bridge Connection: "+SockPeerIP);
|
||||
idletimer = new QTimer(this);
|
||||
idletimer->setInterval(IDLETIMEOUTMINS*60000); //connection timout for idle sockets
|
||||
idletimer->setSingleShot(true);
|
||||
@@ -254,19 +254,40 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){
|
||||
}else if(out.in_struct.name=="auth_ssl"){
|
||||
if(out.in_struct.args.isObject() && out.in_struct.args.toObject().contains("encrypted_string")){
|
||||
//Stage 2: Check the returned encrypted/string
|
||||
qDebug() << "State 2 SSL Auth Request";
|
||||
cur_auth_tok = AUTHSYSTEM->LoginUC(host, JsonValueToString(out.in_struct.args.toObject().value("encrypted_string")) );
|
||||
}else{
|
||||
//Stage 1: Send the client a random string to encrypt with their SSL key
|
||||
QString key = AUTHSYSTEM->GenerateEncCheckString();
|
||||
QJsonObject obj; obj.insert("test_string", key);
|
||||
QJsonObject obj;
|
||||
/*if(out.in_struct.args.toObject().contains("md5_key")){
|
||||
qDebug() << "Encrypted SSL Auth Requested";
|
||||
QString md5 = out.in_struct.args.toObject().value("md5_key").toString(); //Note: This is base64 encoded right now
|
||||
//qDebug() << " - Get pub key for md5";
|
||||
QByteArray pubkey = AUTHSYSTEM->pubkeyForMd5(md5);
|
||||
//qDebug() << " - Generate new Priv key";
|
||||
QByteArray privkey = AUTHSYSTEM->GenerateSSLPrivkey();
|
||||
//Now break up the private key into 128 byte chunks and encrypt with public key for transport
|
||||
//qDebug() << " - Destruct priv key into chunks" << "Length:" << privkey.size();
|
||||
QJsonArray pkeyarr;
|
||||
for(int i=0; i<privkey.size(); i+=64){
|
||||
//qDebug() << " -- i:" << i;
|
||||
pkeyarr << AUTHSYSTEM->encryptString( QString(privkey.mid(i,64)), pubkey);
|
||||
}
|
||||
obj.insert("new_ssl_key", pkeyarr); //send this to the client for re-assembly
|
||||
//Also encrypt the test string with the public key as well
|
||||
//qDebug() << " - Encrypt test string with pubkey";
|
||||
key = AUTHSYSTEM->encryptString( key, pubkey);
|
||||
//qDebug() << " - Done with special SSL section";
|
||||
BRIDGE[REQ.bridgeID].enc_key = privkey;
|
||||
}*/
|
||||
obj.insert("test_string", key);
|
||||
out.out_args = obj;
|
||||
out.CODE = RestOutputStruct::OK;
|
||||
QString msg = out.assembleMessage();
|
||||
if(SOCKET!=0 && !REQ.bridgeID.isEmpty()){
|
||||
//BRIDGE RELAY - alternate format
|
||||
//Need to encrypt the message for output (TO-DO)
|
||||
QString key = BRIDGE[REQ.bridgeID].enc_key;
|
||||
if(!key.isEmpty()){ msg = AUTHSYSTEM->encryptString(msg, key); }
|
||||
//BRIDGE RELAY - alternate format
|
||||
//Note that the Stage 1 SSL auth reply is only partially encrypted (specific variables only, not bulk message encryption)
|
||||
//Now add the destination ID
|
||||
msg.prepend( REQ.bridgeID+"\n");
|
||||
}
|
||||
@@ -383,12 +404,10 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){
|
||||
//Return any information
|
||||
QString msg = out.assembleMessage();
|
||||
if(SOCKET!=0 && !REQ.bridgeID.isEmpty()){
|
||||
//BRIDGE RELAY - alternate format
|
||||
//Need to encrypt the message for output (TO-DO)
|
||||
QString key = BRIDGE[REQ.bridgeID].enc_key;
|
||||
if(!key.isEmpty()){ msg = AUTHSYSTEM->encryptString(msg, key); }
|
||||
//Now add the destination ID
|
||||
msg.prepend( REQ.bridgeID+"\n");
|
||||
//BRIDGE RELAY - alternate format
|
||||
msg = AUTHSYSTEM->encryptString(msg, BRIDGE[REQ.bridgeID].enc_key);
|
||||
//Now add the destination ID
|
||||
msg.prepend( REQ.bridgeID+"\n");
|
||||
}
|
||||
if(out.CODE == RestOutputStruct::FORBIDDEN && SOCKET!=0 && SOCKET->isValid()){
|
||||
this->sendReply(msg);
|
||||
@@ -521,7 +540,7 @@ void WebSocket::EvaluateMessage(const QByteArray &msg){
|
||||
}
|
||||
|
||||
void WebSocket::EvaluateMessage(const QString &msg){
|
||||
//qDebug() << "New Text Message:";
|
||||
qDebug() << "New Text Message:" << msg;
|
||||
if(idletimer->isActive()){ idletimer->stop(); }
|
||||
idletimer->start();
|
||||
EvaluateREST(msg);
|
||||
@@ -606,6 +625,8 @@ void WebSocket::SslError(const QList<QSslError> &err){ //sslErrors() signal
|
||||
}
|
||||
|
||||
void WebSocket::startBridgeAuth(){
|
||||
SockPeerIP = SOCKET->peerAddress().toString();
|
||||
LogManager::log(LogManager::HOST,"New Bridge Connection: "+SockPeerIP);
|
||||
//qDebug() << "Init Bridge Auth...";
|
||||
QJsonObject obj;
|
||||
obj.insert("id", "server_to_bridge_auth");
|
||||
@@ -637,9 +658,7 @@ void WebSocket::EventUpdate(EventWatcher::EVENT_TYPE evtype, QJsonValue msg){
|
||||
for(int i=0; i<conns.length(); i++){
|
||||
if( !BRIDGE[conns[i]].sendEvents.contains(evtype) ){ continue; }
|
||||
//Encrypt the data with the proper key
|
||||
QString key = BRIDGE[conns[i]].enc_key;
|
||||
QString enc_data = raw;
|
||||
if(!key.isEmpty()){ enc_data = AUTHSYSTEM->encryptString(raw, key); }
|
||||
QString enc_data = AUTHSYSTEM->encryptString(raw, BRIDGE[conns[i]].enc_key);
|
||||
//Now add the destination ID
|
||||
enc_data.prepend( conns[i]+"\n");
|
||||
this->emit SendMessage(enc_data);
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
#include "AuthorizationManager.h"
|
||||
|
||||
struct bridge_data{
|
||||
QString enc_key, auth_tok;
|
||||
QByteArray enc_key;
|
||||
QString auth_tok;
|
||||
QList<EventWatcher::EVENT_TYPE> sendEvents;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user