xref: /aosp_15_r20/external/vboot_reference/host/lib/host_signature.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2011 The ChromiumOS Authors
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  *
5  * Host functions for signature generation.
6  */
7 
8 /* TODO: change all 'return 0', 'return 1' into meaningful return codes */
9 
10 #include <openssl/rsa.h>
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <sys/types.h>
15 #include <sys/wait.h>
16 #include <unistd.h>
17 
18 #include "2common.h"
19 #include "2rsa.h"
20 #include "2sha.h"
21 #include "2sysincludes.h"
22 #include "host_common.h"
23 #include "host_signature21.h"
24 
25 /* Invoke [external_signer] command with [pem_file] as an argument, contents of
26  * [inbuf] passed redirected to stdin, and the stdout of the command is put
27  * back into [outbuf].  Returns -1 on error, 0 on success.
28  */
sign_external(uint32_t size,const uint8_t * inbuf,uint8_t * outbuf,uint32_t outbufsize,const char * pem_file,const char * external_signer)29 static int sign_external(uint32_t size, const uint8_t *inbuf, uint8_t *outbuf,
30 			 uint32_t outbufsize, const char *pem_file,
31 			 const char *external_signer)
32 {
33 	int rv = 0, n;
34 	int p_to_c[2], c_to_p[2];  /* pipe descriptors */
35 	pid_t pid;
36 
37 	VB2_DEBUG("Will invoke \"%s %s\" to perform signing.\n"
38 		 "Input to the signer will be provided on standard in.\n"
39 		 "Output of the signer will be read from standard out.\n",
40 		  external_signer, pem_file);
41 
42 	/* Need two pipes since we want to invoke the external_signer as
43 	 * a co-process writing to its stdin and reading from its stdout. */
44 	if (pipe(p_to_c) < 0 || pipe(c_to_p) < 0) {
45 		VB2_DEBUG("pipe() error\n");
46 		return -1;
47 	}
48 	if ((pid = fork()) < 0) {
49 		VB2_DEBUG("fork() error\n");
50 		return -1;
51 	} else if (pid > 0) {  /* Parent. */
52 		close(p_to_c[STDIN_FILENO]);
53 		close(c_to_p[STDOUT_FILENO]);
54 
55 		/* We provide input to the child process (external signer). */
56 		if (write(p_to_c[STDOUT_FILENO], inbuf, size) != size) {
57 			VB2_DEBUG("write() error\n");
58 			rv = -1;
59 		} else {
60 			/* Send EOF to child (signer process). */
61 			close(p_to_c[STDOUT_FILENO]);
62 
63 			do {
64 				n = read(c_to_p[STDIN_FILENO], outbuf,
65 					 outbufsize);
66 				outbuf += n;
67 				outbufsize -= n;
68 			} while (n > 0 && outbufsize);
69 
70 			if (n < 0) {
71 				VB2_DEBUG("read() error\n");
72 				rv = -1;
73 			}
74 		}
75 		if (waitpid(pid, NULL, 0) < 0) {
76 			VB2_DEBUG("waitpid() error\n");
77 			rv = -1;
78 		}
79 	} else {  /* Child. */
80 		close (p_to_c[STDOUT_FILENO]);
81 		close (c_to_p[STDIN_FILENO]);
82 		/* Map the stdin to the first pipe (this pipe gets input
83 		 * from the parent) */
84 		if (STDIN_FILENO != p_to_c[STDIN_FILENO]) {
85 			if (dup2(p_to_c[STDIN_FILENO], STDIN_FILENO) !=
86 			    STDIN_FILENO) {
87 				VB2_DEBUG("stdin dup2() failed\n");
88 				close(p_to_c[0]);
89 				return -1;
90 			}
91 		}
92 		/* Map the stdout to the second pipe (this pipe sends back
93 		 * signer output to the parent) */
94 		if (STDOUT_FILENO != c_to_p[STDOUT_FILENO]) {
95 			if (dup2(c_to_p[STDOUT_FILENO], STDOUT_FILENO) !=
96 			    STDOUT_FILENO) {
97 				VB2_DEBUG("stdout dup2() failed\n");
98 				close(c_to_p[STDOUT_FILENO]);
99 				return -1;
100 			}
101 		}
102 		/* External signer is invoked here. */
103 		if (execl(external_signer, external_signer, pem_file,
104 			  (char *) 0) < 0) {
105 			VB2_DEBUG("execl() of external signer failed\n");
106 		}
107 	}
108 	return rv;
109 }
110 
vb2_external_signature(const uint8_t * data,uint32_t size,const char * key_file,uint32_t key_algorithm,const char * external_signer)111 struct vb2_signature *vb2_external_signature(const uint8_t *data, uint32_t size,
112 					     const char *key_file,
113 					     uint32_t key_algorithm,
114 					     const char *external_signer)
115 {
116 	struct vb2_hash hash;
117 
118 	/* Calculate the digest */
119 	if (VB2_SUCCESS != vb2_hash_calculate(false, data, size,
120 					      vb2_crypto_to_hash(key_algorithm),
121 					      &hash))
122 		return NULL;
123 
124 	uint32_t digest_info_size = 0;
125 	const uint8_t *digest_info = NULL;
126 	if (VB2_SUCCESS != vb2_digest_info(hash.algo,
127 					   &digest_info, &digest_info_size))
128 		return NULL;
129 
130 	int digest_size = vb2_digest_size(hash.algo);
131 	uint8_t *signature_digest;
132 	uint64_t signature_digest_len = digest_size + digest_info_size;
133 
134 	int rv;
135 
136 	/* Prepend the digest info to the digest */
137 	signature_digest = calloc(signature_digest_len, 1);
138 	if (!signature_digest)
139 		return NULL;
140 
141 	memcpy(signature_digest, digest_info, digest_info_size);
142 	memcpy(signature_digest + digest_info_size, hash.raw, digest_size);
143 
144 	/* Allocate output signature */
145 	uint32_t sig_size =
146 		vb2_rsa_sig_size(vb2_crypto_to_signature(key_algorithm));
147 	struct vb2_signature *sig = vb2_alloc_signature(sig_size, size);
148 	if (!sig) {
149 		free(signature_digest);
150 		return NULL;
151 	}
152 
153 	/* Sign the signature_digest into our output buffer */
154 	rv = sign_external(signature_digest_len,    /* Input length */
155 			   signature_digest,        /* Input data */
156 			   vb2_signature_data_mutable(sig),  /* Output sig */
157 			   sig_size,                /* Max Output sig size */
158 			   key_file,                /* Key file to use */
159 			   external_signer);        /* External cmd to invoke */
160 	free(signature_digest);
161 
162 	if (-1 == rv) {
163 		VB2_DEBUG("RSA_private_encrypt() failed.\n");
164 		free(sig);
165 		return NULL;
166 	}
167 
168 	/* Return the signature */
169 	return sig;
170 }
171