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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_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  */
49 static 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  */
68 static 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 */
85  offset = pem_next ( data, len, offset );
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  */
104 int 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  */
192 static 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  */
219 static 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 */
237 struct image_type pem_image_type __image_type ( PROBE_NORMAL ) = {
238  .name = "PEM",
239  .probe = pem_image_probe,
240  .asn1 = pem_image_asn1,
241 };
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
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
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
static int pem_marker(const void *data, size_t len, size_t offset, const char *marker)
Locate boundary marker line.
Definition: pem.c:68
Error codes.
const void * data
Read-only data.
Definition: image.h:51
#define DBGC(...)
Definition: compiler.h:505
An executable image type.
Definition: image.h:95
#define ENOENT
No such file or directory.
Definition: errno.h:515
static size_t pem_next(const void *data, size_t len, size_t offset)
Locate next line.
Definition: pem.c:49
#define PROBE_NORMAL
Normal image probe priority.
Definition: image.h:156
int base64_decode(const char *encoded, void *data, size_t len)
Base64-decode string.
Definition: base64.c:92
An executable image.
Definition: image.h:24
struct image_type pem_image_type __image_type(PROBE_NORMAL)
PEM image type.
char * name
Name of this image type.
Definition: image.h:97
void * memchr(const void *src, int character, size_t len)
Find character within a memory region.
Definition: string.c:136
#define ENOMEM
Not enough space.
Definition: errno.h:535
static size_t base64_decoded_max_len(const char *encoded)
Calculate maximum length of base64-decoded string.
Definition: base64.h:35
void * memcpy(void *dest, const void *src, size_t len) __nonnull
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
Assertions.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
Executable images.
ASN.1 encoding.
PEM-encoded ASN.1 data.
ring len
Length.
Definition: dwmac.h:231
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
size_t len
Length of raw file image.
Definition: image.h:56
size_t strlen(const char *src)
Get length of string.
Definition: string.c:244
uint32_t next
Next descriptor address.
Definition: dwmac.h:22
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:621
Base64 encoding.
FILE_SECBOOT(PERMITTED)
#define PEM_END
Post-encapsulation boundary marker.
Definition: pem.h:21
uint32_t end
Ending offset.
Definition: netvsc.h:18
uint8_t data[48]
Additional event data.
Definition: ena.h:22
static int pem_image_probe(struct image *image)
Probe PEM image.
Definition: pem.c:192
#define PEM_BEGIN
Pre-encapsulation boundary marker.
Definition: pem.h:18
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:115
char * name
Name.
Definition: image.h:38
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
An ASN.1 object cursor.
Definition: asn1.h:21
struct eth_slow_marker_tlv marker
Marker information.
Definition: eth_slow.h:15