You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

clientcert.c 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * Copyright (C) 2012 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. FILE_LICENCE ( GPL2_OR_LATER );
  20. #include <stdint.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <ipxe/dhcp.h>
  24. #include <ipxe/settings.h>
  25. #include <ipxe/clientcert.h>
  26. /** @file
  27. *
  28. * Client certificate store
  29. *
  30. * Life would in theory be easier if we could use a single file to
  31. * hold both the certificate and corresponding private key.
  32. * Unfortunately, the only common format which supports this is
  33. * PKCS#12 (aka PFX), which is too ugly to be allowed anywhere near my
  34. * codebase. See, for reference and amusement:
  35. *
  36. * http://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html
  37. *
  38. */
  39. /* Sanity checks */
  40. #if defined(CERTIFICATE) && ! defined(PRIVATE_KEY)
  41. #warning "Attempting to embed certificate with no corresponding private key"
  42. #endif
  43. #if defined(PRIVATE_KEY) && ! defined(CERTIFICATE)
  44. #warning "Attempting to embed private key with no corresponding certificate"
  45. #endif
  46. /* Allow client certificates to be overridden if not explicitly specified */
  47. #ifdef CERTIFICATE
  48. #define ALLOW_CERT_OVERRIDE 0
  49. #else
  50. #define ALLOW_CERT_OVERRIDE 1
  51. #endif
  52. /* Raw client certificate data */
  53. extern char client_certificate_data[];
  54. extern char client_certificate_len[];
  55. __asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"
  56. "\nclient_certificate_data:\n\t"
  57. #ifdef CERTIFICATE
  58. ".incbin \"" CERTIFICATE "\"\n\t"
  59. #endif /* CERTIFICATE */
  60. ".size client_certificate_data, ( . - client_certificate_data )\n\t"
  61. ".equ client_certificate_len, ( . - client_certificate_data )\n\t"
  62. ".previous\n\t" );
  63. /* Raw client private key data */
  64. extern char client_private_key_data[];
  65. extern char client_private_key_len[];
  66. __asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"
  67. "\nclient_private_key_data:\n\t"
  68. #ifdef PRIVATE_KEY
  69. ".incbin \"" PRIVATE_KEY "\"\n\t"
  70. #endif /* PRIVATE_KEY */
  71. ".size client_private_key_data, ( . - client_private_key_data )\n\t"
  72. ".equ client_private_key_len, ( . - client_private_key_data )\n\t"
  73. ".previous\n\t" );
  74. /** Client certificate */
  75. struct client_certificate client_certificate = {
  76. .data = client_certificate_data,
  77. .len = ( ( size_t ) client_certificate_len ),
  78. };
  79. /** Client private key */
  80. struct client_private_key client_private_key = {
  81. .data = client_private_key_data,
  82. .len = ( ( size_t ) client_private_key_len ),
  83. };
  84. /** Client certificate setting */
  85. static struct setting cert_setting __setting ( SETTING_CRYPTO ) = {
  86. .name = "cert",
  87. .description = "Client certificate",
  88. .tag = DHCP_EB_CERT,
  89. .type = &setting_type_hex,
  90. };
  91. /** Client private key setting */
  92. static struct setting privkey_setting __setting ( SETTING_CRYPTO ) = {
  93. .name = "privkey",
  94. .description = "Client private key",
  95. .tag = DHCP_EB_KEY,
  96. .type = &setting_type_hex,
  97. };
  98. /**
  99. * Apply client certificate store configuration settings
  100. *
  101. * @ret rc Return status code
  102. */
  103. static int clientcert_apply_settings ( void ) {
  104. static void *cert = NULL;
  105. static void *key = NULL;
  106. int len;
  107. int rc;
  108. /* Allow client certificate to be overridden only if
  109. * not explicitly specified at build time.
  110. */
  111. if ( ALLOW_CERT_OVERRIDE ) {
  112. /* Restore default client certificate */
  113. client_certificate.data = client_certificate_data;
  114. client_certificate.len = ( ( size_t ) client_certificate_len );
  115. /* Fetch new client certificate, if any */
  116. free ( cert );
  117. len = fetch_setting_copy ( NULL, &cert_setting, &cert );
  118. if ( len < 0 ) {
  119. rc = len;
  120. DBGC ( &client_certificate, "CLIENTCERT cannot fetch "
  121. "client certificate: %s\n", strerror ( rc ) );
  122. return rc;
  123. }
  124. if ( cert ) {
  125. client_certificate.data = cert;
  126. client_certificate.len = len;
  127. }
  128. /* Restore default client private key */
  129. client_private_key.data = client_private_key_data;
  130. client_private_key.len = ( ( size_t ) client_private_key_len );
  131. /* Fetch new client private key, if any */
  132. free ( key );
  133. len = fetch_setting_copy ( NULL, &privkey_setting, &key );
  134. if ( len < 0 ) {
  135. rc = len;
  136. DBGC ( &client_certificate, "CLIENTCERT cannot fetch "
  137. "client private key: %s\n", strerror ( rc ) );
  138. return rc;
  139. }
  140. if ( key ) {
  141. client_private_key.data = key;
  142. client_private_key.len = len;
  143. }
  144. }
  145. /* Debug */
  146. if ( have_client_certificate() ) {
  147. DBGC ( &client_certificate, "CLIENTCERT using %s "
  148. "certificate:\n", ( cert ? "external" : "built-in" ) );
  149. DBGC_HDA ( &client_certificate, 0, client_certificate.data,
  150. client_certificate.len );
  151. DBGC ( &client_certificate, "CLIENTCERT using %s private "
  152. "key:\n", ( key ? "external" : "built-in" ) );
  153. DBGC_HDA ( &client_certificate, 0, client_private_key.data,
  154. client_private_key.len );
  155. } else {
  156. DBGC ( &client_certificate, "CLIENTCERT has no certificate\n" );
  157. }
  158. return 0;
  159. }
  160. /** Client certificate store settings applicator */
  161. struct settings_applicator clientcert_applicator __settings_applicator = {
  162. .apply = clientcert_apply_settings,
  163. };