cLib: First implementation of gj_generate_ssh_keys

We're using openssl to do so. This was quite confusing.

This really helped https://stackoverflow.com/a/12750816/147435
This commit is contained in:
Vishesh Handa
2019-05-29 13:46:32 +02:00
parent d518b49623
commit 4c1ff7fc50
2 changed files with 135 additions and 67 deletions

View File

@ -1,4 +1,4 @@
CC=clang CC=clang
test: gitjournal.c test.c keygen.c test: gitjournal.c test.c keygen.c
$(CC) -o test -g test.c gitjournal.c keygen.c -lgit2 $(CC) -o test -g test.c gitjournal.c keygen.c -lgit2 -lssl -lcrypto

View File

@ -4,90 +4,158 @@
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
/* #include <memory.h>
#include <libssh/libssh.h>
#include <libssh/callbacks.h>
*/
#define UNUSED(x) (void)(x) #include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
void change_pubickey_comment(const char *filename, const char *comment) static unsigned char pSshHeader[11] = {0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2D, 0x72, 0x73, 0x61};
static int SshEncodeBuffer(unsigned char *pEncoding, int bufferLen, unsigned char *pBuffer)
{ {
FILE *fp = fopen(filename, "r"); int adjustedLen = bufferLen, index;
char buff[10000]; if (*pBuffer & 0x80)
fgets(buff, 10000, fp); {
fclose(fp); adjustedLen++;
pEncoding[4] = 0;
// Remove the comment index = 5;
char *end = strchr(strchr(buff, ' ') + 1, ' '); }
int len = end - buff + 1; else
buff[len] = 0; {
index = 4;
// Add custom comment }
strcat(buff, comment); pEncoding[0] = (unsigned char)(adjustedLen >> 24);
strcat(buff, "\n"); pEncoding[1] = (unsigned char)(adjustedLen >> 16);
pEncoding[2] = (unsigned char)(adjustedLen >> 8);
// Write the file back pEncoding[3] = (unsigned char)(adjustedLen);
fp = fopen(filename, "w"); memcpy(&pEncoding[index], pBuffer, bufferLen);
fputs(buff, fp); return index + bufferLen;
fclose(fp);
} }
void gj_ssh_log_callback(int priority, const char *function, const char *buffer, void *userdata) int write_rsa_public_key(RSA *pRsa, const char *file_path, const char *comment)
{ {
UNUSED(userdata); int iRet = 0;
char log_str[1024]; int encodingLength = 0;
sprintf(log_str, "LIB_SSH P%d : %s : %s\n", priority, function, buffer); int index = 0;
gj_log(log_str); unsigned char *nBytes = NULL, *eBytes = NULL;
unsigned char *pEncoding = NULL;
FILE *pFile = NULL;
BIO *bio, *b64;
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
const BIGNUM *pRsa_mod = NULL;
const BIGNUM *pRsa_exp = NULL;
RSA_get0_key(pRsa, &pRsa_mod, &pRsa_exp, NULL);
// reading the modulus
int nLen = BN_num_bytes(pRsa_mod);
nBytes = (unsigned char *)malloc(nLen);
BN_bn2bin(pRsa_mod, nBytes);
// reading the public exponent
int eLen = BN_num_bytes(pRsa_exp);
eBytes = (unsigned char *)malloc(eLen);
BN_bn2bin(pRsa_exp, eBytes);
printf("nLen: %d\n", nLen);
printf("nLen2: %d\n", BN_num_bytes(pRsa_mod));
printf("eLen: %d\n", eLen);
encodingLength = 11 + 4 + eLen + 4 + nLen;
// correct depending on the MSB of e and N
if (eBytes[0] & 0x80)
encodingLength++;
if (nBytes[0] & 0x80)
encodingLength++;
pEncoding = (unsigned char *)malloc(encodingLength);
memset(pEncoding, 0, encodingLength);
memcpy(pEncoding, pSshHeader, 11);
index = SshEncodeBuffer(&pEncoding[11], eLen, eBytes);
index = SshEncodeBuffer(&pEncoding[11 + index], nLen, nBytes);
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
pFile = fopen(file_path, "w");
bio = BIO_new_fp(pFile, BIO_CLOSE);
BIO_printf(bio, "ssh-rsa ");
bio = BIO_push(b64, bio);
BIO_write(bio, pEncoding, encodingLength);
BIO_flush(bio);
bio = BIO_pop(b64);
BIO_printf(bio, " %s\n", comment);
BIO_flush(bio);
BIO_free_all(bio);
BIO_free(b64);
error:
if (pFile)
fclose(pFile);
free(nBytes);
free(eBytes);
free(pEncoding);
EVP_cleanup();
ERR_free_strings();
return iRet;
} }
int gj_generate_ssh_keys(const char *private_key_path, int gj_generate_ssh_keys(const char *private_key_path,
const char *public_key_path, const char *comment) const char *public_key_path, const char *comment)
{ {
UNUSED(private_key_path); int ret = 0;
UNUSED(public_key_path); RSA *rsa = NULL;
UNUSED(comment);
return 1; BIGNUM *bne = NULL;
/* BIO *bp_private = NULL;
ssh_key key;
int err;
ssh_set_log_level(SSH_LOG_FUNCTIONS); int bits = 1024 * 4;
ssh_set_log_callback(gj_ssh_log_callback); unsigned long e = RSA_F4;
err = ssh_pki_generate(SSH_KEYTYPE_RSA, 4096, &key); // Generate rsa key
if (err != SSH_OK) bne = BN_new();
ret = BN_set_word(bne, e);
if (ret != 1)
{ {
gj_log("LIBSSH: ssh_pki_generate failed\n"); goto cleanup;
//printf("Error: %s", ssh_get_error());
return err;
} }
char *password = ""; rsa = RSA_new();
err = ssh_pki_export_privkey_file(key, password, NULL, NULL, private_key_path); ret = RSA_generate_key_ex(rsa, bits, bne, NULL);
if (err != SSH_OK) if (ret != 1)
{ {
gj_log("LIBSSH: ssh_pki_export_privkey_file failed\n"); goto cleanup;
return err;
} }
err = ssh_pki_export_pubkey_file(key, public_key_path); // Save private key
if (err != SSH_OK) bp_private = BIO_new_file(private_key_path, "w+");
ret = PEM_write_bio_RSAPrivateKey(bp_private, rsa, NULL, NULL, 0, NULL, NULL);
if (ret != 1)
{ {
gj_log("LIBSSH: ssh_pki_export_pubkey_file failed\n");
return err; goto cleanup;
} }
ssh_key_free(key); // Save public key
ret = write_rsa_public_key(rsa, public_key_path, comment);
change_pubickey_comment(public_key_path, comment); if (ret != 1)
{
// Change file permissions goto cleanup;
char mode[] = "0600"; }
int modeInt = strtol(mode, 0, 8);
chmod(private_key_path, modeInt); cleanup:
BIO_free_all(bp_private);
return 0; RSA_free(rsa);
*/ BN_free(bne);
return (ret == 1);
} }