/* * Copyright (C) 2016 Michael Brown . * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * You can also choose to distribute this program under the terms of * the Unmodified Binary Distribution Licence (as given in the file * COPYING.UBDL), provided that you have satisfied its requirements. */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include #include #include #include #include /** @file * * DER-encoded ASN.1 data * */ /** * Extract ASN.1 object from DER data * * @v data DER data * @v len Length of DER data * @v offset Offset within data * @v cursor ASN.1 cursor to fill in * @ret next Offset to next object, or negative error * * The caller is responsible for eventually calling free() on the * allocated ASN.1 cursor. */ int der_asn1 ( userptr_t data, size_t len, size_t offset, struct asn1_cursor **cursor ) { size_t remaining; void *raw; /* Sanity check */ assert ( offset <= len ); remaining = ( len - offset ); /* Allocate cursor and data buffer */ *cursor = malloc ( sizeof ( **cursor ) + remaining ); if ( ! *cursor ) return -ENOMEM; raw = ( ( ( void * ) *cursor ) + sizeof ( **cursor ) ); /* Populate cursor and data buffer */ (*cursor)->data = raw; (*cursor)->len = remaining; copy_from_user ( raw, data, offset, remaining ); /* Shrink cursor */ asn1_shrink_any ( *cursor ); return ( offset + (*cursor)->len ); } /** * Probe DER image * * @v image DER image * @ret rc Return status code */ static int der_image_probe ( struct image *image ) { struct asn1_cursor cursor; uint8_t buf[8]; size_t extra; int rc; /* Sanity check: no realistic DER image can be smaller than this */ if ( image->len < sizeof ( buf ) ) return -ENOEXEC; /* Prepare partial cursor */ cursor.data = buf; cursor.len = sizeof ( buf ); copy_from_user ( buf, image->data, 0, sizeof ( buf ) ); extra = ( image->len - sizeof ( buf ) ); /* Check that image begins with an ASN.1 sequence object */ if ( ( rc = asn1_enter_partial ( &cursor, ASN1_SEQUENCE, &extra ) ) != 0 ) { DBGC ( image, "DER %s is not valid ASN.1: %s\n", image->name, strerror ( rc ) ); return rc; } /* Check that image comprises a single well-formed ASN.1 object */ if ( extra != ( image->len - sizeof ( buf ) ) ) { DBGC ( image, "DER %s is not single ASN.1\n", image->name ); return -ENOEXEC; } return 0; } /** * Extract ASN.1 object from DER image * * @v image DER image * @v offset Offset within image * @v cursor ASN.1 cursor to fill in * @ret next Offset to next image, or negative error * * The caller is responsible for eventually calling free() on the * allocated ASN.1 cursor. */ static int der_image_asn1 ( struct image *image, size_t offset, struct asn1_cursor **cursor ) { int next; int rc; /* Extract ASN.1 object */ if ( ( next = der_asn1 ( image->data, image->len, offset, cursor ) ) < 0 ) { rc = next; DBGC ( image, "DER %s could not extract ASN.1: %s\n", image->name, strerror ( rc ) ); return rc; } return next; } /** DER image type */ struct image_type der_image_type __image_type ( PROBE_NORMAL ) = { .name = "DER", .probe = der_image_probe, .asn1 = der_image_asn1, };