| /* |
| * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>. |
| * |
| * 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 <stdint.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <ipxe/dhcp.h> |
| #include <ipxe/settings.h> |
| #include <ipxe/x509.h> |
| #include <ipxe/privkey.h> |
| |
| /** @file |
| * |
| * Private key |
| * |
| * Life would in theory be easier if we could use a single file to |
| * hold both the certificate and corresponding private key. |
| * Unfortunately, the only common format which supports this is |
| * PKCS#12 (aka PFX), which is too ugly to be allowed anywhere near my |
| * codebase. See, for reference and amusement: |
| * |
| * http://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html |
| */ |
| |
| /* Allow private key to be overridden if not explicitly specified */ |
| #ifdef PRIVATE_KEY |
| #define ALLOW_KEY_OVERRIDE 0 |
| #else |
| #define ALLOW_KEY_OVERRIDE 1 |
| #endif |
| |
| /* Raw private key data */ |
| extern char private_key_data[]; |
| extern char private_key_len[]; |
| __asm__ ( ".section \".rodata\", \"a\", " PROGBITS "\n\t" |
| "\nprivate_key_data:\n\t" |
| #ifdef PRIVATE_KEY |
| ".incbin \"" PRIVATE_KEY "\"\n\t" |
| #endif /* PRIVATE_KEY */ |
| ".size private_key_data, ( . - private_key_data )\n\t" |
| ".equ private_key_len, ( . - private_key_data )\n\t" |
| ".previous\n\t" ); |
| |
| /** Private key */ |
| struct private_key private_key = { |
| .refcnt = REF_INIT ( ref_no_free ), |
| .builder = { |
| .data = private_key_data, |
| .len = ( ( size_t ) private_key_len ), |
| }, |
| }; |
| |
| /** Default private key */ |
| static struct asn1_cursor default_private_key = { |
| .data = private_key_data, |
| .len = ( ( size_t ) private_key_len ), |
| }; |
| |
| /** Private key setting */ |
| static struct setting privkey_setting __setting ( SETTING_CRYPTO, privkey ) = { |
| .name = "privkey", |
| .description = "Private key", |
| .tag = DHCP_EB_KEY, |
| .type = &setting_type_hex, |
| }; |
| |
| /** |
| * Free private key |
| * |
| * @v refcnt Reference counter |
| */ |
| void privkey_free ( struct refcnt *refcnt ) { |
| struct private_key *key = |
| container_of ( refcnt, struct private_key, refcnt ); |
| |
| free ( key->builder.data ); |
| free ( key ); |
| } |
| |
| /** |
| * Apply private key configuration settings |
| * |
| * @ret rc Return status code |
| */ |
| static int privkey_apply_settings ( void ) { |
| static void *key_data = NULL; |
| int len; |
| |
| /* Allow private key to be overridden only if not explicitly |
| * specified at build time. |
| */ |
| if ( ALLOW_KEY_OVERRIDE ) { |
| |
| /* Restore default private key */ |
| memcpy ( &private_key.builder, &default_private_key, |
| sizeof ( private_key.builder ) ); |
| |
| /* Fetch new private key, if any */ |
| free ( key_data ); |
| if ( ( len = fetch_raw_setting_copy ( NULL, &privkey_setting, |
| &key_data ) ) >= 0 ) { |
| private_key.builder.data = key_data; |
| private_key.builder.len = len; |
| } |
| } |
| |
| /* Debug */ |
| if ( private_key.builder.len ) { |
| DBGC ( &private_key, "PRIVKEY using %s private key:\n", |
| ( key_data ? "external" : "built-in" ) ); |
| DBGC_HDA ( &private_key, 0, private_key.builder.data, |
| private_key.builder.len ); |
| } else { |
| DBGC ( &private_key, "PRIVKEY has no private key\n" ); |
| } |
| |
| return 0; |
| } |
| |
| /** Private key settings applicator */ |
| struct settings_applicator privkey_applicator __settings_applicator = { |
| .apply = privkey_apply_settings, |
| }; |