ssh_key pki_private_key_from_base64(const char *b64_key, const char *passphrase, ssh_auth_callback auth_fn, void *auth_data) { gcry_sexp_t dsa = NULL; gcry_sexp_t rsa = NULL; ssh_key key = NULL; enum ssh_keytypes_e type; int valid; /* needed for gcrypt initialization */ if (ssh_init() < 0) { return NULL; } type = pki_privatekey_type_from_string(b64_key); if (type == SSH_KEYTYPE_UNKNOWN) { SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key."); return NULL; } switch (type) { case SSH_KEYTYPE_DSS: if (passphrase == NULL) { if (auth_fn) { valid = b64decode_dsa_privatekey(b64_key, &dsa, auth_fn, auth_data, "Passphrase for private key:"); } else { valid = b64decode_dsa_privatekey(b64_key, &dsa, NULL, NULL, NULL); } } else { valid = b64decode_dsa_privatekey(b64_key, &dsa, NULL, (void *) passphrase, NULL); } if (!valid) { SSH_LOG(SSH_LOG_WARN, "Parsing private key"); goto fail; } break; case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA1: if (passphrase == NULL) { if (auth_fn) { valid = b64decode_rsa_privatekey(b64_key, &rsa, auth_fn, auth_data, "Passphrase for private key:"); } else { valid = b64decode_rsa_privatekey(b64_key, &rsa, NULL, NULL, NULL); } } else { valid = b64decode_rsa_privatekey(b64_key, &rsa, NULL, (void *)passphrase, NULL); } if (!valid) { SSH_LOG(SSH_LOG_WARN, "Parsing private key"); goto fail; } break; case SSH_KEYTYPE_ED25519: /* Cannot open ed25519 keys with libgcrypt */ case SSH_KEYTYPE_ECDSA: case SSH_KEYTYPE_UNKNOWN: default: SSH_LOG(SSH_LOG_WARN, "Unkown or invalid private key type %d", type); return NULL; } key = ssh_key_new(); if (key == NULL) { goto fail; } key->type = type; key->type_c = ssh_key_type_to_char(type); key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC; key->dsa = dsa; key->rsa = rsa; return key; fail: ssh_key_free(key); gcry_sexp_release(dsa); gcry_sexp_release(rsa); return NULL; }
ssh_key pki_private_key_from_base64(const char *b64_key, const char *passphrase, ssh_auth_callback auth_fn, void *auth_data) { ssh_key key = NULL; mbedtls_pk_context *rsa = NULL; mbedtls_pk_context *ecdsa = NULL; ed25519_privkey *ed25519 = NULL; enum ssh_keytypes_e type; int valid; /* mbedtls pk_parse_key expects strlen to count the 0 byte */ size_t b64len = strlen(b64_key) + 1; unsigned char tmp[MAX_PASSPHRASE_SIZE] = {0}; type = pki_privatekey_type_from_string(b64_key); if (type == SSH_KEYTYPE_UNKNOWN) { SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key."); return NULL; } switch (type) { case SSH_KEYTYPE_RSA: rsa = malloc(sizeof(mbedtls_pk_context)); if (rsa == NULL) { return NULL; } mbedtls_pk_init(rsa); if (passphrase == NULL) { if (auth_fn) { valid = auth_fn("Passphrase for private key:", (char *) tmp, MAX_PASSPHRASE_SIZE, 0, 0, auth_data); if (valid < 0) { return NULL; } /* TODO fix signedness and strlen */ valid = mbedtls_pk_parse_key(rsa, (const unsigned char *) b64_key, b64len, tmp, strnlen((const char *) tmp, MAX_PASSPHRASE_SIZE)); } else { valid = mbedtls_pk_parse_key(rsa, (const unsigned char *) b64_key, b64len, NULL, 0); } } else { valid = mbedtls_pk_parse_key(rsa, (const unsigned char *) b64_key, b64len, (const unsigned char *) passphrase, strnlen(passphrase, MAX_PASSPHRASE_SIZE)); } if (valid != 0) { char error_buf[100]; mbedtls_strerror(valid, error_buf, 100); SSH_LOG(SSH_LOG_WARN,"Parsing private key %s", error_buf); goto fail; } break; case SSH_KEYTYPE_ECDSA: ecdsa = malloc(sizeof(mbedtls_pk_context)); if (ecdsa == NULL) { return NULL; } mbedtls_pk_init(ecdsa); if (passphrase == NULL) { if (auth_fn) { valid = auth_fn("Passphrase for private key:", (char *) tmp, MAX_PASSPHRASE_SIZE, 0, 0, auth_data); if (valid < 0) { return NULL; } valid = mbedtls_pk_parse_key(ecdsa, (const unsigned char *) b64_key, b64len, tmp, strnlen((const char *) tmp, MAX_PASSPHRASE_SIZE)); } else { valid = mbedtls_pk_parse_key(ecdsa, (const unsigned char *) b64_key, b64len, NULL, 0); } } else { valid = mbedtls_pk_parse_key(ecdsa, (const unsigned char *) b64_key, b64len, (const unsigned char *) passphrase, strnlen(passphrase, MAX_PASSPHRASE_SIZE)); } if (valid != 0) { char error_buf[100]; mbedtls_strerror(valid, error_buf, 100); SSH_LOG(SSH_LOG_WARN,"Parsing private key %s", error_buf); goto fail; } break; case SSH_KEYTYPE_ED25519: /* Cannot open ed25519 keys with libmbedcrypto */ default: SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key type %d", type); return NULL; } key = ssh_key_new(); if (key == NULL) { goto fail; } key->type = type; key->type_c = ssh_key_type_to_char(type); key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC; key->rsa = rsa; if (ecdsa != NULL) { mbedtls_ecp_keypair *keypair = mbedtls_pk_ec(*ecdsa); key->ecdsa = malloc(sizeof(mbedtls_ecdsa_context)); if (key->ecdsa == NULL) { goto fail; } mbedtls_ecdsa_init(key->ecdsa); mbedtls_ecdsa_from_keypair(key->ecdsa, keypair); mbedtls_pk_free(ecdsa); SAFE_FREE(ecdsa); } else { key->ecdsa = NULL; } key->ed25519_privkey = ed25519; rsa = NULL; ecdsa = NULL; if (key->type == SSH_KEYTYPE_ECDSA) { key->ecdsa_nid = pki_key_ecdsa_to_nid(key->ecdsa); key->type_c = pki_key_ecdsa_nid_to_name(key->ecdsa_nid); } return key; fail: ssh_key_free(key); if (rsa != NULL) { mbedtls_pk_free(rsa); SAFE_FREE(rsa); } if (ecdsa != NULL) { mbedtls_pk_free(ecdsa); SAFE_FREE(ecdsa); } return NULL; }
ssh_key pki_private_key_from_base64(ssh_session session, const char *b64_key, const char *passphrase) { BIO *mem = NULL; DSA *dsa = NULL; RSA *rsa = NULL; ssh_key key; enum ssh_keytypes_e type; /* needed for openssl initialization */ if (ssh_init() < 0) { return NULL; } type = pki_privatekey_type_from_string(b64_key); if (type == SSH_KEYTYPE_UNKNOWN) { ssh_set_error(session, SSH_FATAL, "Unknown or invalid private key."); return NULL; } mem = BIO_new_mem_buf((void*)b64_key, -1); switch (type) { case SSH_KEYTYPE_DSS: if (passphrase == NULL) { if (session->common.callbacks && session->common.callbacks->auth_function) { dsa = PEM_read_bio_DSAPrivateKey(mem, NULL, pem_get_password, session); } else { /* openssl uses its own callback to get the passphrase here */ dsa = PEM_read_bio_DSAPrivateKey(mem, NULL, NULL, NULL); } } else { dsa = PEM_read_bio_DSAPrivateKey(mem, NULL, NULL, (void *) passphrase); } BIO_free(mem); if (dsa == NULL) { ssh_set_error(session, SSH_FATAL, "Parsing private key: %s", ERR_error_string(ERR_get_error(), NULL)); return NULL; } break; case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA1: if (passphrase == NULL) { if (session->common.callbacks && session->common.callbacks->auth_function) { rsa = PEM_read_bio_RSAPrivateKey(mem, NULL, pem_get_password, session); } else { /* openssl uses its own callback to get the passphrase here */ rsa = PEM_read_bio_RSAPrivateKey(mem, NULL, NULL, NULL); } } else { rsa = PEM_read_bio_RSAPrivateKey(mem, NULL, NULL, (void *) passphrase); } BIO_free(mem); if (rsa == NULL) { ssh_set_error(session, SSH_FATAL, "Parsing private key: %s", ERR_error_string(ERR_get_error(),NULL)); return NULL; } break; case SSH_KEYTYPE_ECDSA: case SSH_KEYTYPE_UNKNOWN: BIO_free(mem); ssh_set_error(session, SSH_FATAL, "Unkown or invalid private key type %d", type); return NULL; } key = ssh_key_new(); if (key == NULL) { goto fail; } key->type = type; key->type_c = ssh_key_type_to_char(type); key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC; key->dsa = dsa; key->rsa = rsa; return key; fail: ssh_key_free(key); DSA_free(dsa); RSA_free(rsa); return NULL; }