XBPS Library API 20240111
The X Binary Package System
pubkey2fp.c
1/*
2 * An implementation of convertion from OpenSSL to OpenSSH public key format
3 *
4 * Copyright (c) 2008 Mounir IDRASSI <mounir.idrassi@idrix.fr>. All rights reserved.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
8 * or FITNESS FOR A PARTICULAR PURPOSE.
9 */
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <assert.h>
14
15#include <openssl/bio.h>
16#include <openssl/evp.h>
17#include <openssl/pem.h>
18#include <openssl/err.h>
19
20#include "xbps_api_impl.h"
21
22static unsigned char pSshHeader[11] = {
23 0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2D, 0x72, 0x73, 0x61
24};
25
26static int
27SshEncodeBuffer(unsigned char *pEncoding, int bufferLen, unsigned char *pBuffer)
28{
29 int adjustedLen = bufferLen, index;
30
31 if (*pBuffer & 0x80) {
32 adjustedLen++;
33 pEncoding[4] = 0;
34 index = 5;
35 } else {
36 index = 4;
37 }
38 pEncoding[0] = (unsigned char) (adjustedLen >> 24);
39 pEncoding[1] = (unsigned char) (adjustedLen >> 16);
40 pEncoding[2] = (unsigned char) (adjustedLen >> 8);
41 pEncoding[3] = (unsigned char) (adjustedLen );
42 memcpy(&pEncoding[index], pBuffer, bufferLen);
43 return index + bufferLen;
44}
45
46static char *
47fp2str(unsigned const char *fp, unsigned int len)
48{
49 unsigned int i, c = 0;
50 char res[48], cur[4];
51
52 for (i = 0; i < len; i++) {
53 if (i > 0)
54 c = i*3;
55 sprintf(cur, "%02x", fp[i]);
56 res[c] = cur[0];
57 res[c+1] = cur[1];
58 res[c+2] = ':';
59 }
60 res[c+2] = '\0';
61
62 return strdup(res);
63}
64
65char *
66xbps_pubkey2fp(xbps_data_t pubkey)
67{
68 EVP_MD_CTX *mdctx = NULL;
69 EVP_PKEY *pPubKey = NULL;
70 RSA *pRsa = NULL;
71 BIO *bio = NULL;
72 const void *pubkeydata;
73 unsigned char md_value[EVP_MAX_MD_SIZE];
74 const BIGNUM *n, *e;
75 unsigned char *nBytes = NULL, *eBytes = NULL, *pEncoding = NULL;
76 unsigned int md_len = 0;
77 char *hexfpstr = NULL;
78 int index = 0, nLen = 0, eLen = 0, encodingLength = 0;
79
80 ERR_load_crypto_strings();
81 OpenSSL_add_all_algorithms();
82
83 mdctx = EVP_MD_CTX_new();
84 assert(mdctx);
85 pubkeydata = xbps_data_data_nocopy(pubkey);
86 bio = BIO_new_mem_buf(pubkeydata, xbps_data_size(pubkey));
87 assert(bio);
88
89 pPubKey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
90 if (!pPubKey) {
91 xbps_dbg_printf(
92 "unable to decode public key from the given file: %s\n",
93 ERR_error_string(ERR_get_error(), NULL));
94 goto out;
95 }
96
97 if (EVP_PKEY_base_id(pPubKey) != EVP_PKEY_RSA) {
98 xbps_dbg_printf("only RSA public keys are currently supported\n");
99 goto out;
100 }
101
102 pRsa = EVP_PKEY_get1_RSA(pPubKey);
103 if (!pRsa) {
104 xbps_dbg_printf("failed to get RSA public key : %s\n",
105 ERR_error_string(ERR_get_error(), NULL));
106 goto out;
107 }
108
109 RSA_get0_key(pRsa, &n, &e, NULL);
110 // reading the modulus
111 nLen = BN_num_bytes(n);
112 nBytes = (unsigned char*) malloc(nLen);
113 if (nBytes == NULL)
114 goto out;
115 BN_bn2bin(n, nBytes);
116
117 // reading the public exponent
118 eLen = BN_num_bytes(e);
119 eBytes = (unsigned char*) malloc(eLen);
120 if (eBytes == NULL)
121 goto out;
122 BN_bn2bin(e, eBytes);
123
124 encodingLength = 11 + 4 + eLen + 4 + nLen;
125 // correct depending on the MSB of e and N
126 if (eBytes[0] & 0x80)
127 encodingLength++;
128 if (nBytes[0] & 0x80)
129 encodingLength++;
130
131 pEncoding = malloc(encodingLength);
132 assert(pEncoding);
133
134 memcpy(pEncoding, pSshHeader, 11);
135
136 index = SshEncodeBuffer(&pEncoding[11], eLen, eBytes);
137 (void)SshEncodeBuffer(&pEncoding[11 + index], nLen, nBytes);
138
139 /*
140 * Compute the RSA fingerprint (MD5).
141 */
142 EVP_MD_CTX_init(mdctx);
143 EVP_DigestInit_ex(mdctx, EVP_md5(), NULL);
144 EVP_DigestUpdate(mdctx, pEncoding, encodingLength);
145 if (EVP_DigestFinal_ex(mdctx, md_value, &md_len) == 0)
146 goto out;
147 EVP_MD_CTX_free(mdctx);
148 mdctx = NULL;
149 /*
150 * Convert result to a compatible OpenSSH hex fingerprint.
151 */
152 hexfpstr = fp2str(md_value, md_len);
153
154out:
155 if (mdctx)
156 EVP_MD_CTX_free(mdctx);
157 if (bio)
158 BIO_free_all(bio);
159 if (pRsa)
160 RSA_free(pRsa);
161 if (pPubKey)
162 EVP_PKEY_free(pPubKey);
163 if (nBytes)
164 free(nBytes);
165 if (eBytes)
166 free(eBytes);
167 if (pEncoding)
168 free(pEncoding);
169
170 return hexfpstr;
171}
char * xbps_pubkey2fp(xbps_data_t pubkey)
Definition pubkey2fp.c:66