summaryrefslogtreecommitdiffstats
path: root/src/util/cert/libcrypto/cert.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/cert/libcrypto/cert.c')
-rw-r--r--src/util/cert/libcrypto/cert.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/util/cert/libcrypto/cert.c b/src/util/cert/libcrypto/cert.c
index 1a250f60d..01f9554b9 100644
--- a/src/util/cert/libcrypto/cert.c
+++ b/src/util/cert/libcrypto/cert.c
@@ -166,3 +166,96 @@ done:
return ret;
}
+
+#define SSH_RSA_HEADER "ssh-rsa"
+#define SSH_RSA_HEADER_LEN (sizeof(SSH_RSA_HEADER) - 1)
+
+errno_t cert_to_ssh_key(TALLOC_CTX *mem_ctx, const char *ca_db,
+ const uint8_t *der_blob, size_t der_size,
+ uint8_t **key, size_t *key_size)
+{
+ int ret;
+ size_t size;
+ const unsigned char *d;
+ uint8_t *buf = NULL;
+ size_t c;
+ X509 *cert = NULL;
+ EVP_PKEY *cert_pub_key = NULL;
+ int modulus_len;
+ unsigned char modulus[OPENSSL_RSA_MAX_MODULUS_BITS/8];
+ int exponent_len;
+ unsigned char exponent[OPENSSL_RSA_MAX_PUBEXP_BITS/8];
+
+ if (der_blob == NULL || der_size == 0) {
+ return EINVAL;
+ }
+
+ d = (const unsigned char *) der_blob;
+
+ cert = d2i_X509(NULL, &d, (int) der_size);
+ if (cert == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "d2i_X509 failed.\n");
+ return EINVAL;
+ }
+
+ /* TODO: verify certificate !!!!! */
+
+ cert_pub_key = X509_get_pubkey(cert);
+ if (cert_pub_key == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "X509_get_pubkey failed.\n");
+ ret = EIO;
+ goto done;
+ }
+
+ if (cert_pub_key->type != EVP_PKEY_RSA) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Expected RSA public key, found unsupported [%d].\n",
+ cert_pub_key->type);
+ ret = EINVAL;
+ goto done;
+ }
+
+ modulus_len = BN_bn2bin(cert_pub_key->pkey.rsa->n, modulus);
+ exponent_len = BN_bn2bin(cert_pub_key->pkey.rsa->e, exponent);
+
+ size = SSH_RSA_HEADER_LEN + 3 * sizeof(uint32_t)
+ + modulus_len
+ + exponent_len
+ + 1; /* see comment about missing 00 below */
+
+ buf = talloc_size(mem_ctx, size);
+ if (buf == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ c = 0;
+
+ SAFEALIGN_SET_UINT32(buf, htobe32(SSH_RSA_HEADER_LEN), &c);
+ safealign_memcpy(&buf[c], SSH_RSA_HEADER, SSH_RSA_HEADER_LEN, &c);
+ SAFEALIGN_SET_UINT32(&buf[c], htobe32(exponent_len), &c);
+ safealign_memcpy(&buf[c], exponent, exponent_len, &c);
+
+ /* Adding missing 00 which afaik is added to make sure
+ * the bigint is handled as positive number */
+ /* TODO: make a better check if 00 must be added or not, e.g. ... & 0x80)
+ */
+ SAFEALIGN_SET_UINT32(&buf[c], htobe32(modulus_len + 1), &c);
+ SAFEALIGN_SETMEM_VALUE(&buf[c], '\0', unsigned char, &c);
+ safealign_memcpy(&buf[c], modulus, modulus_len, &c);
+
+ *key = buf;
+ *key_size = size;
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(buf);
+ }
+ EVP_PKEY_free(cert_pub_key);
+ X509_free(cert);
+
+ return ret;
+}