|  | @@ -27,10 +27,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
		
	
		
			
			| 27 | 27 |  #include <errno.h>
 | 
		
	
		
			
			| 28 | 28 |  #include <assert.h>
 | 
		
	
		
			
			| 29 | 29 |  #include <ipxe/asn1.h>
 | 
		
	
		
			
			| 30 |  | -#include <ipxe/pem.h>
 | 
		
	
		
			
			| 31 | 30 |  #include <ipxe/base64.h>
 | 
		
	
		
			
			| 32 | 31 |  #include <ipxe/uaccess.h>
 | 
		
	
		
			
			| 33 | 32 |  #include <ipxe/image.h>
 | 
		
	
		
			
			|  | 33 | +#include <ipxe/pem.h>
 | 
		
	
		
			
			| 34 | 34 |  
 | 
		
	
		
			
			| 35 | 35 |  /** @file
 | 
		
	
		
			
			| 36 | 36 |   *
 | 
		
	
	
		
			
			|  | @@ -41,95 +41,98 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
		
	
		
			
			| 41 | 41 |  /**
 | 
		
	
		
			
			| 42 | 42 |   * Locate next line
 | 
		
	
		
			
			| 43 | 43 |   *
 | 
		
	
		
			
			| 44 |  | - * @v image		PEM image
 | 
		
	
		
			
			|  | 44 | + * @v data		PEM data
 | 
		
	
		
			
			|  | 45 | + * @v len		Length of PEM data
 | 
		
	
		
			
			| 45 | 46 |   * @v offset		Starting offset
 | 
		
	
		
			
			| 46 | 47 |   * @ret next		Offset to next line
 | 
		
	
		
			
			| 47 | 48 |   */
 | 
		
	
		
			
			| 48 |  | -static size_t pem_next ( struct image *image, size_t offset ) {
 | 
		
	
		
			
			|  | 49 | +static size_t pem_next ( userptr_t data, size_t len, size_t offset ) {
 | 
		
	
		
			
			| 49 | 50 |  	off_t eol;
 | 
		
	
		
			
			| 50 | 51 |  
 | 
		
	
		
			
			| 51 | 52 |  	/* Find and skip next newline character, if any */
 | 
		
	
		
			
			| 52 |  | -	eol = memchr_user ( image->data, offset, '\n', ( image->len - offset ));
 | 
		
	
		
			
			|  | 53 | +	eol = memchr_user ( data, offset, '\n', ( len - offset ) );
 | 
		
	
		
			
			| 53 | 54 |  	if ( eol < 0 )
 | 
		
	
		
			
			| 54 |  | -		return image->len;
 | 
		
	
		
			
			|  | 55 | +		return len;
 | 
		
	
		
			
			| 55 | 56 |  	return ( eol + 1 );
 | 
		
	
		
			
			| 56 | 57 |  }
 | 
		
	
		
			
			| 57 | 58 |  
 | 
		
	
		
			
			| 58 | 59 |  /**
 | 
		
	
		
			
			| 59 | 60 |   * Locate boundary marker line
 | 
		
	
		
			
			| 60 | 61 |   *
 | 
		
	
		
			
			| 61 |  | - * @v image		PEM image
 | 
		
	
		
			
			|  | 62 | + * @v data		PEM data
 | 
		
	
		
			
			|  | 63 | + * @v len		Length of PEM data
 | 
		
	
		
			
			| 62 | 64 |   * @v offset		Starting offset
 | 
		
	
		
			
			| 63 | 65 |   * @v marker		Boundary marker
 | 
		
	
		
			
			| 64 | 66 |   * @ret offset		Offset to boundary marker line, or negative error
 | 
		
	
		
			
			| 65 | 67 |   */
 | 
		
	
		
			
			| 66 |  | -static int pem_marker ( struct image *image, size_t offset,
 | 
		
	
		
			
			|  | 68 | +static int pem_marker ( userptr_t data, size_t len, size_t offset,
 | 
		
	
		
			
			| 67 | 69 |  			const char *marker ) {
 | 
		
	
		
			
			| 68 | 70 |  	char buf[ strlen ( marker ) ];
 | 
		
	
		
			
			| 69 | 71 |  
 | 
		
	
		
			
			| 70 | 72 |  	/* Sanity check */
 | 
		
	
		
			
			| 71 |  | -	assert ( offset <= image->len );
 | 
		
	
		
			
			|  | 73 | +	assert ( offset <= len );
 | 
		
	
		
			
			| 72 | 74 |  
 | 
		
	
		
			
			| 73 | 75 |  	/* Scan for marker at start of line */
 | 
		
	
		
			
			| 74 |  | -	while ( offset < image->len ) {
 | 
		
	
		
			
			|  | 76 | +	while ( offset < len ) {
 | 
		
	
		
			
			| 75 | 77 |  
 | 
		
	
		
			
			| 76 | 78 |  		/* Check for marker */
 | 
		
	
		
			
			| 77 |  | -		if ( ( image->len - offset ) < sizeof ( buf ) )
 | 
		
	
		
			
			|  | 79 | +		if ( ( len - offset ) < sizeof ( buf ) )
 | 
		
	
		
			
			| 78 | 80 |  			break;
 | 
		
	
		
			
			| 79 |  | -		copy_from_user ( buf, image->data, offset, sizeof ( buf ) );
 | 
		
	
		
			
			|  | 81 | +		copy_from_user ( buf, data, offset, sizeof ( buf ) );
 | 
		
	
		
			
			| 80 | 82 |  		if ( memcmp ( buf, marker, sizeof ( buf ) ) == 0 )
 | 
		
	
		
			
			| 81 | 83 |  			return offset;
 | 
		
	
		
			
			| 82 | 84 |  
 | 
		
	
		
			
			| 83 | 85 |  		/* Move to next line */
 | 
		
	
		
			
			| 84 |  | -		offset = pem_next ( image, offset );
 | 
		
	
		
			
			| 85 |  | -		assert ( offset <= image->len );
 | 
		
	
		
			
			|  | 86 | +		offset = pem_next ( data, len, offset );
 | 
		
	
		
			
			|  | 87 | +		assert ( offset <= len );
 | 
		
	
		
			
			| 86 | 88 |  	}
 | 
		
	
		
			
			| 87 | 89 |  
 | 
		
	
		
			
			| 88 | 90 |  	return -ENOENT;
 | 
		
	
		
			
			| 89 | 91 |  }
 | 
		
	
		
			
			| 90 | 92 |  
 | 
		
	
		
			
			| 91 | 93 |  /**
 | 
		
	
		
			
			| 92 |  | - * Extract ASN.1 object from image
 | 
		
	
		
			
			|  | 94 | + * Extract ASN.1 object from PEM data
 | 
		
	
		
			
			| 93 | 95 |   *
 | 
		
	
		
			
			| 94 |  | - * @v image		PEM image
 | 
		
	
		
			
			| 95 |  | - * @v offset		Offset within image
 | 
		
	
		
			
			|  | 96 | + * @v data		PEM data
 | 
		
	
		
			
			|  | 97 | + * @v len		Length of PEM data
 | 
		
	
		
			
			|  | 98 | + * @v offset		Offset within data
 | 
		
	
		
			
			| 96 | 99 |   * @v cursor		ASN.1 cursor to fill in
 | 
		
	
		
			
			| 97 |  | - * @ret next		Offset to next image, or negative error
 | 
		
	
		
			
			|  | 100 | + * @ret next		Offset to next object, or negative error
 | 
		
	
		
			
			| 98 | 101 |   *
 | 
		
	
		
			
			| 99 | 102 |   * The caller is responsible for eventually calling free() on the
 | 
		
	
		
			
			| 100 | 103 |   * allocated ASN.1 cursor.
 | 
		
	
		
			
			| 101 | 104 |   */
 | 
		
	
		
			
			| 102 |  | -static int pem_asn1 ( struct image *image, size_t offset,
 | 
		
	
		
			
			| 103 |  | -		      struct asn1_cursor **cursor ) {
 | 
		
	
		
			
			|  | 105 | +int pem_asn1 ( userptr_t data, size_t len, size_t offset,
 | 
		
	
		
			
			|  | 106 | +	       struct asn1_cursor **cursor ) {
 | 
		
	
		
			
			| 104 | 107 |  	size_t encoded_len;
 | 
		
	
		
			
			| 105 | 108 |  	size_t decoded_max_len;
 | 
		
	
		
			
			| 106 | 109 |  	char *encoded;
 | 
		
	
		
			
			| 107 | 110 |  	void *decoded;
 | 
		
	
		
			
			|  | 111 | +	int decoded_len;
 | 
		
	
		
			
			| 108 | 112 |  	int begin;
 | 
		
	
		
			
			| 109 | 113 |  	int end;
 | 
		
	
		
			
			| 110 |  | -	int len;
 | 
		
	
		
			
			| 111 | 114 |  	int rc;
 | 
		
	
		
			
			| 112 | 115 |  
 | 
		
	
		
			
			| 113 | 116 |  	/* Locate and skip BEGIN marker */
 | 
		
	
		
			
			| 114 |  | -	begin = pem_marker ( image, offset, PEM_BEGIN );
 | 
		
	
		
			
			|  | 117 | +	begin = pem_marker ( data, len, offset, PEM_BEGIN );
 | 
		
	
		
			
			| 115 | 118 |  	if ( begin < 0 ) {
 | 
		
	
		
			
			| 116 | 119 |  		rc = begin;
 | 
		
	
		
			
			| 117 |  | -		DBGC ( image, "PEM %s [%#zx,%#zx) missing BEGIN marker: %s\n",
 | 
		
	
		
			
			| 118 |  | -		       image->name, offset, image->len, strerror ( rc ) );
 | 
		
	
		
			
			|  | 120 | +		DBGC ( data, "PEM [%#zx,%#zx) missing BEGIN marker: %s\n",
 | 
		
	
		
			
			|  | 121 | +		       offset, len, strerror ( rc ) );
 | 
		
	
		
			
			| 119 | 122 |  		goto err_begin;
 | 
		
	
		
			
			| 120 | 123 |  	}
 | 
		
	
		
			
			| 121 |  | -	begin = pem_next ( image, begin );
 | 
		
	
		
			
			|  | 124 | +	begin = pem_next ( data, len, begin );
 | 
		
	
		
			
			| 122 | 125 |  
 | 
		
	
		
			
			| 123 | 126 |  	/* Locate and skip END marker */
 | 
		
	
		
			
			| 124 |  | -	end = pem_marker ( image, begin, PEM_END );
 | 
		
	
		
			
			|  | 127 | +	end = pem_marker ( data, len, begin, PEM_END );
 | 
		
	
		
			
			| 125 | 128 |  	if ( end < 0 ) {
 | 
		
	
		
			
			| 126 | 129 |  		rc = end;
 | 
		
	
		
			
			| 127 |  | -		DBGC ( image, "PEM %s [%#zx,%#zx) missing END marker: %s\n",
 | 
		
	
		
			
			| 128 |  | -		       image->name, offset, image->len, strerror ( rc ) );
 | 
		
	
		
			
			|  | 130 | +		DBGC ( data, "PEM [%#zx,%#zx) missing END marker: %s\n",
 | 
		
	
		
			
			|  | 131 | +		       offset, len, strerror ( rc ) );
 | 
		
	
		
			
			| 129 | 132 |  		goto err_end;
 | 
		
	
		
			
			| 130 | 133 |  	}
 | 
		
	
		
			
			| 131 | 134 |  	encoded_len = ( end - begin );
 | 
		
	
		
			
			| 132 |  | -	end = pem_next ( image, end );
 | 
		
	
		
			
			|  | 135 | +	end = pem_next ( data, len, end );
 | 
		
	
		
			
			| 133 | 136 |  
 | 
		
	
		
			
			| 134 | 137 |  	/* Extract Base64-encoded data */
 | 
		
	
		
			
			| 135 | 138 |  	encoded = malloc ( encoded_len + 1 /* NUL */ );
 | 
		
	
	
		
			
			|  | @@ -137,7 +140,7 @@ static int pem_asn1 ( struct image *image, size_t offset,
 | 
		
	
		
			
			| 137 | 140 |  		rc = -ENOMEM;
 | 
		
	
		
			
			| 138 | 141 |  		goto err_alloc_encoded;
 | 
		
	
		
			
			| 139 | 142 |  	}
 | 
		
	
		
			
			| 140 |  | -	copy_from_user ( encoded, image->data, begin, encoded_len );
 | 
		
	
		
			
			|  | 143 | +	copy_from_user ( encoded, data, begin, encoded_len );
 | 
		
	
		
			
			| 141 | 144 |  	encoded[encoded_len] = '\0';
 | 
		
	
		
			
			| 142 | 145 |  
 | 
		
	
		
			
			| 143 | 146 |  	/* Allocate cursor and data buffer */
 | 
		
	
	
		
			
			|  | @@ -150,15 +153,14 @@ static int pem_asn1 ( struct image *image, size_t offset,
 | 
		
	
		
			
			| 150 | 153 |  	decoded = ( ( ( void * ) *cursor ) + sizeof ( **cursor ) );
 | 
		
	
		
			
			| 151 | 154 |  
 | 
		
	
		
			
			| 152 | 155 |  	/* Decode Base64-encoded data */
 | 
		
	
		
			
			| 153 |  | -	len = base64_decode ( encoded, decoded, decoded_max_len );
 | 
		
	
		
			
			| 154 |  | -	if ( len < 0 ) {
 | 
		
	
		
			
			| 155 |  | -		rc = len;
 | 
		
	
		
			
			| 156 |  | -		DBGC ( image, "PEM %s could not decode: %s\n",
 | 
		
	
		
			
			| 157 |  | -		       image->name, strerror ( rc ) );
 | 
		
	
		
			
			|  | 156 | +	decoded_len = base64_decode ( encoded, decoded, decoded_max_len );
 | 
		
	
		
			
			|  | 157 | +	if ( decoded_len < 0 ) {
 | 
		
	
		
			
			|  | 158 | +		rc = decoded_len;
 | 
		
	
		
			
			|  | 159 | +		DBGC ( data, "PEM could not decode: %s\n", strerror ( rc ) );
 | 
		
	
		
			
			| 158 | 160 |  		goto err_decode;
 | 
		
	
		
			
			| 159 | 161 |  	}
 | 
		
	
		
			
			| 160 | 162 |  	(*cursor)->data = decoded;
 | 
		
	
		
			
			| 161 |  | -	(*cursor)->len = len;
 | 
		
	
		
			
			|  | 163 | +	(*cursor)->len = decoded_len;
 | 
		
	
		
			
			| 162 | 164 |  	assert ( (*cursor)->len <= decoded_max_len );
 | 
		
	
		
			
			| 163 | 165 |  
 | 
		
	
		
			
			| 164 | 166 |  	/* Free Base64-encoded data */
 | 
		
	
	
		
			
			|  | @@ -166,8 +168,8 @@ static int pem_asn1 ( struct image *image, size_t offset,
 | 
		
	
		
			
			| 166 | 168 |  
 | 
		
	
		
			
			| 167 | 169 |  	/* Update offset and skip any unencapsulated trailer */
 | 
		
	
		
			
			| 168 | 170 |  	offset = end;
 | 
		
	
		
			
			| 169 |  | -	if ( pem_marker ( image, offset, PEM_BEGIN ) < 0 )
 | 
		
	
		
			
			| 170 |  | -		offset = image->len;
 | 
		
	
		
			
			|  | 171 | +	if ( pem_marker ( data, len, offset, PEM_BEGIN ) < 0 )
 | 
		
	
		
			
			|  | 172 | +		offset = len;
 | 
		
	
		
			
			| 171 | 173 |  
 | 
		
	
		
			
			| 172 | 174 |  	return offset;
 | 
		
	
		
			
			| 173 | 175 |  
 | 
		
	
	
		
			
			|  | @@ -188,11 +190,14 @@ static int pem_asn1 ( struct image *image, size_t offset,
 | 
		
	
		
			
			| 188 | 190 |   * @v image		PEM image
 | 
		
	
		
			
			| 189 | 191 |   * @ret rc		Return status code
 | 
		
	
		
			
			| 190 | 192 |   */
 | 
		
	
		
			
			| 191 |  | -static int pem_probe ( struct image *image ) {
 | 
		
	
		
			
			|  | 193 | +static int pem_image_probe ( struct image *image ) {
 | 
		
	
		
			
			|  | 194 | +	int offset;
 | 
		
	
		
			
			| 192 | 195 |  	int rc;
 | 
		
	
		
			
			| 193 | 196 |  
 | 
		
	
		
			
			| 194 | 197 |  	/* Check that image contains a BEGIN marker */
 | 
		
	
		
			
			| 195 |  | -	if ( ( rc = pem_marker ( image, 0, PEM_BEGIN ) ) < 0 ) {
 | 
		
	
		
			
			|  | 198 | +	if ( ( offset = pem_marker ( image->data, image->len, 0,
 | 
		
	
		
			
			|  | 199 | +				     PEM_BEGIN ) ) < 0 ) {
 | 
		
	
		
			
			|  | 200 | +		rc = offset;
 | 
		
	
		
			
			| 196 | 201 |  		DBGC ( image, "PEM %s has no BEGIN marker: %s\n",
 | 
		
	
		
			
			| 197 | 202 |  		       image->name, strerror ( rc ) );
 | 
		
	
		
			
			| 198 | 203 |  		return rc;
 | 
		
	
	
		
			
			|  | @@ -201,9 +206,37 @@ static int pem_probe ( struct image *image ) {
 | 
		
	
		
			
			| 201 | 206 |  	return 0;
 | 
		
	
		
			
			| 202 | 207 |  }
 | 
		
	
		
			
			| 203 | 208 |  
 | 
		
	
		
			
			|  | 209 | +/**
 | 
		
	
		
			
			|  | 210 | + * Extract ASN.1 object from image
 | 
		
	
		
			
			|  | 211 | + *
 | 
		
	
		
			
			|  | 212 | + * @v image		PEM image
 | 
		
	
		
			
			|  | 213 | + * @v offset		Offset within image
 | 
		
	
		
			
			|  | 214 | + * @v cursor		ASN.1 cursor to fill in
 | 
		
	
		
			
			|  | 215 | + * @ret next		Offset to next image, or negative error
 | 
		
	
		
			
			|  | 216 | + *
 | 
		
	
		
			
			|  | 217 | + * The caller is responsible for eventually calling free() on the
 | 
		
	
		
			
			|  | 218 | + * allocated ASN.1 cursor.
 | 
		
	
		
			
			|  | 219 | + */
 | 
		
	
		
			
			|  | 220 | +static int pem_image_asn1 ( struct image *image, size_t offset,
 | 
		
	
		
			
			|  | 221 | +			    struct asn1_cursor **cursor ) {
 | 
		
	
		
			
			|  | 222 | +	int next;
 | 
		
	
		
			
			|  | 223 | +	int rc;
 | 
		
	
		
			
			|  | 224 | +
 | 
		
	
		
			
			|  | 225 | +	/* Extract ASN.1 object */
 | 
		
	
		
			
			|  | 226 | +	if ( ( next = pem_asn1 ( image->data, image->len, offset,
 | 
		
	
		
			
			|  | 227 | +				 cursor ) ) < 0 ) {
 | 
		
	
		
			
			|  | 228 | +		rc = next;
 | 
		
	
		
			
			|  | 229 | +		DBGC ( image, "PEM %s could not extract ASN.1: %s\n",
 | 
		
	
		
			
			|  | 230 | +		       image->name, strerror ( rc ) );
 | 
		
	
		
			
			|  | 231 | +		return rc;
 | 
		
	
		
			
			|  | 232 | +	}
 | 
		
	
		
			
			|  | 233 | +
 | 
		
	
		
			
			|  | 234 | +	return next;
 | 
		
	
		
			
			|  | 235 | +}
 | 
		
	
		
			
			|  | 236 | +
 | 
		
	
		
			
			| 204 | 237 |  /** PEM image type */
 | 
		
	
		
			
			| 205 | 238 |  struct image_type pem_image_type __image_type ( PROBE_NORMAL ) = {
 | 
		
	
		
			
			| 206 | 239 |  	.name = "PEM",
 | 
		
	
		
			
			| 207 |  | -	.probe = pem_probe,
 | 
		
	
		
			
			| 208 |  | -	.asn1 = pem_asn1,
 | 
		
	
		
			
			|  | 240 | +	.probe = pem_image_probe,
 | 
		
	
		
			
			|  | 241 | +	.asn1 = pem_image_asn1,
 | 
		
	
		
			
			| 209 | 242 |  };
 |