iPXE
pem.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <stdlib.h>
28#include <errno.h>
29#include <assert.h>
30#include <ipxe/asn1.h>
31#include <ipxe/base64.h>
32#include <ipxe/image.h>
33#include <ipxe/pem.h>
34
35/** @file
36 *
37 * PEM-encoded ASN.1 data
38 *
39 */
40
41/**
42 * Locate next line
43 *
44 * @v data PEM data
45 * @v len Length of PEM data
46 * @v offset Starting offset
47 * @ret next Offset to next line
48 */
49static size_t pem_next ( const void *data, size_t len, size_t offset ) {
50 const void *sep;
51
52 /* Find and skip next newline character, if any */
53 sep = memchr ( ( data + offset ), '\n', ( len - offset ) );
54 if ( ! sep )
55 return len;
56 return ( ( sep - data ) + 1 );
57}
58
59/**
60 * Locate boundary marker line
61 *
62 * @v data PEM data
63 * @v len Length of PEM data
64 * @v offset Starting offset
65 * @v marker Boundary marker
66 * @ret offset Offset to boundary marker line, or negative error
67 */
68static int pem_marker ( const void *data, size_t len, size_t offset,
69 const char *marker ) {
70 size_t marker_len = strlen ( marker );
71
72 /* Sanity check */
73 assert ( offset <= len );
74
75 /* Scan for marker at start of line */
76 while ( offset < len ) {
77
78 /* Check for marker */
79 if ( ( len - offset ) < marker_len )
80 break;
81 if ( memcmp ( ( data + offset ), marker, marker_len ) == 0 )
82 return offset;
83
84 /* Move to next line */
86 assert ( offset <= len );
87 }
88
89 return -ENOENT;
90}
91
92/**
93 * Extract ASN.1 object from PEM data
94 *
95 * @v data PEM data
96 * @v len Length of PEM data
97 * @v offset Offset within data
98 * @v cursor ASN.1 cursor to fill in
99 * @ret next Offset to next object, or negative error
100 *
101 * The caller is responsible for eventually calling free() on the
102 * allocated ASN.1 cursor.
103 */
104int pem_asn1 ( const void *data, size_t len, size_t offset,
105 struct asn1_cursor **cursor ) {
106 size_t encoded_len;
107 size_t decoded_max_len;
108 char *encoded;
109 void *decoded;
110 int decoded_len;
111 int begin;
112 int end;
113 int rc;
114
115 /* Locate and skip BEGIN marker */
116 begin = pem_marker ( data, len, offset, PEM_BEGIN );
117 if ( begin < 0 ) {
118 rc = begin;
119 DBGC ( data, "PEM [%#zx,%#zx) missing BEGIN marker: %s\n",
120 offset, len, strerror ( rc ) );
121 goto err_begin;
122 }
123 begin = pem_next ( data, len, begin );
124
125 /* Locate and skip END marker */
126 end = pem_marker ( data, len, begin, PEM_END );
127 if ( end < 0 ) {
128 rc = end;
129 DBGC ( data, "PEM [%#zx,%#zx) missing END marker: %s\n",
130 offset, len, strerror ( rc ) );
131 goto err_end;
132 }
133 encoded_len = ( end - begin );
134 end = pem_next ( data, len, end );
135
136 /* Extract Base64-encoded data */
137 encoded = malloc ( encoded_len + 1 /* NUL */ );
138 if ( ! encoded ) {
139 rc = -ENOMEM;
140 goto err_alloc_encoded;
141 }
142 memcpy ( encoded, ( data + begin ), encoded_len );
143 encoded[encoded_len] = '\0';
144
145 /* Allocate cursor and data buffer */
146 decoded_max_len = base64_decoded_max_len ( encoded );
147 *cursor = malloc ( sizeof ( **cursor ) + decoded_max_len );
148 if ( ! *cursor ) {
149 rc = -ENOMEM;
150 goto err_alloc_cursor;
151 }
152 decoded = ( ( ( void * ) *cursor ) + sizeof ( **cursor ) );
153
154 /* Decode Base64-encoded data */
155 decoded_len = base64_decode ( encoded, decoded, decoded_max_len );
156 if ( decoded_len < 0 ) {
157 rc = decoded_len;
158 DBGC ( data, "PEM could not decode: %s\n", strerror ( rc ) );
159 goto err_decode;
160 }
161 (*cursor)->data = decoded;
162 (*cursor)->len = decoded_len;
163 assert ( (*cursor)->len <= decoded_max_len );
164
165 /* Free Base64-encoded data */
166 free ( encoded );
167
168 /* Update offset and skip any unencapsulated trailer */
169 offset = end;
170 if ( pem_marker ( data, len, offset, PEM_BEGIN ) < 0 )
171 offset = len;
172
173 return offset;
174
175 err_decode:
176 free ( *cursor );
177 *cursor = NULL;
178 err_alloc_cursor:
179 free ( encoded );
180 err_alloc_encoded:
181 err_end:
182 err_begin:
183 return rc;
184}
185
186/**
187 * Probe PEM image
188 *
189 * @v image PEM image
190 * @ret rc Return status code
191 */
192static int pem_image_probe ( struct image *image ) {
193 int offset;
194 int rc;
195
196 /* Check that image contains a BEGIN marker */
197 if ( ( offset = pem_marker ( image->data, image->len, 0,
198 PEM_BEGIN ) ) < 0 ) {
199 rc = offset;
200 DBGC ( image, "PEM %s has no BEGIN marker: %s\n",
201 image->name, strerror ( rc ) );
202 return rc;
203 }
204
205 return 0;
206}
207
208/**
209 * Extract ASN.1 object from image
210 *
211 * @v image PEM image
212 * @v offset Offset within image
213 * @v cursor ASN.1 cursor to fill in
214 * @ret next Offset to next image, or negative error
215 *
216 * The caller is responsible for eventually calling free() on the
217 * allocated ASN.1 cursor.
218 */
219static int pem_image_asn1 ( struct image *image, size_t offset,
220 struct asn1_cursor **cursor ) {
221 int next;
222 int rc;
223
224 /* Extract ASN.1 object */
225 if ( ( next = pem_asn1 ( image->data, image->len, offset,
226 cursor ) ) < 0 ) {
227 rc = next;
228 DBGC ( image, "PEM %s could not extract ASN.1: %s\n",
229 image->name, strerror ( rc ) );
230 return rc;
231 }
232
233 return next;
234}
235
236/** PEM image type */
237struct image_type pem_image_type __image_type ( PROBE_NORMAL ) = {
238 .name = "PEM",
239 .probe = pem_image_probe,
240 .asn1 = pem_image_asn1,
241};
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
ASN.1 encoding.
Assertions.
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
int base64_decode(const char *encoded, void *data, size_t len)
Base64-decode string.
Definition base64.c:92
Base64 encoding.
static size_t base64_decoded_max_len(const char *encoded)
Calculate maximum length of base64-decoded string.
Definition base64.h:35
uint16_t offset
Offset to command line.
Definition bzimage.h:3
uint32_t next
Next descriptor address.
Definition dwmac.h:11
ring len
Length.
Definition dwmac.h:226
uint8_t data[48]
Additional event data.
Definition ena.h:11
Error codes.
struct eth_slow_marker_tlv marker
Marker information.
Definition eth_slow.h:3
#define DBGC(...)
Definition compiler.h:505
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOENT
No such file or directory.
Definition errno.h:515
#define ENOMEM
Not enough space.
Definition errno.h:535
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
Executable images.
#define PROBE_NORMAL
Normal image probe priority.
Definition image.h:156
#define __image_type(probe_order)
An executable image type.
Definition image.h:170
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * malloc(size_t size)
Allocate memory.
Definition malloc.c:621
uint32_t end
Ending offset.
Definition netvsc.h:7
int pem_asn1(const void *data, size_t len, size_t offset, struct asn1_cursor **cursor)
Extract ASN.1 object from PEM data.
Definition pem.c:104
static size_t pem_next(const void *data, size_t len, size_t offset)
Locate next line.
Definition pem.c:49
static int pem_marker(const void *data, size_t len, size_t offset, const char *marker)
Locate boundary marker line.
Definition pem.c:68
static int pem_image_probe(struct image *image)
Probe PEM image.
Definition pem.c:192
static int pem_image_asn1(struct image *image, size_t offset, struct asn1_cursor **cursor)
Extract ASN.1 object from image.
Definition pem.c:219
PEM-encoded ASN.1 data.
#define PEM_BEGIN
Pre-encapsulation boundary marker.
Definition pem.h:18
#define PEM_END
Post-encapsulation boundary marker.
Definition pem.h:21
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
void * memchr(const void *src, int character, size_t len)
Find character within a memory region.
Definition string.c:136
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
size_t strlen(const char *src)
Get length of string.
Definition string.c:244
An ASN.1 object cursor.
Definition asn1.h:21
An executable image type.
Definition image.h:95
An executable image.
Definition image.h:24
const void * data
Read-only data.
Definition image.h:51
char * name
Name.
Definition image.h:38
size_t len
Length of raw file image.
Definition image.h:56