diff options
158 files changed, 5195 insertions, 3910 deletions
diff --git a/contrib/cloud/aws-import b/contrib/cloud/aws-import index ace0058..3b6b522 100755 --- a/contrib/cloud/aws-import +++ b/contrib/cloud/aws-import @@ -22,11 +22,12 @@ def detect_architecture(image): return 'x86_64' -def create_snapshot(region, description, image): +def create_snapshot(region, description, image, tags): """Create an EBS snapshot""" client = boto3.client('ebs', region_name=region) snapshot = client.start_snapshot(VolumeSize=1, - Description=description) + Description=description, + Tags=tags) snapshot_id = snapshot['SnapshotId'] with open(image, 'rb') as fh: for block in count(): @@ -46,21 +47,42 @@ def create_snapshot(region, description, image): return snapshot_id -def import_image(region, name, architecture, image, public, overwrite): - """Import an AMI image""" +def delete_images(region, filters, retain): client = boto3.client('ec2', region_name=region) resource = boto3.resource('ec2', region_name=region) - description = '%s (%s)' % (name, architecture) - images = client.describe_images(Filters=[{'Name': 'name', - 'Values': [description]}]) - if overwrite and images['Images']: - images = images['Images'][0] - image_id = images['ImageId'] - snapshot_id = images['BlockDeviceMappings'][0]['Ebs']['SnapshotId'] + images = client.describe_images(Owners=['self'], Filters=filters) + old_images = sorted(images['Images'], key=lambda x: x['CreationDate']) + if retain > 0: + old_images = old_images[:-retain] + for image in old_images: + image_id = image['ImageId'] + snapshot_id = image['BlockDeviceMappings'][0]['Ebs']['SnapshotId'] resource.Image(image_id).deregister() resource.Snapshot(snapshot_id).delete() + + +def import_image(region, name, family, architecture, image, public, overwrite, + retain): + """Import an AMI image""" + client = boto3.client('ec2', region_name=region) + resource = boto3.resource('ec2', region_name=region) + description = '%s (%s)' % (name, architecture) + tags = [ + {'Key': 'family', 'Value': family}, + {'Key': 'architecture', 'Value': architecture}, + ] + if overwrite: + filters = [{'Name': 'name', 'Values': [description]}] + delete_images(region=region, filters=filters, retain=0) + if retain is not None: + filters = [ + {'Name': 'tag:family', 'Values': [family]}, + {'Name': 'tag:architecture', 'Values': [architecture]}, + {'Name': 'is-public', 'Values': [str(public).lower()]}, + ] + delete_images(region=region, filters=filters, retain=retain) snapshot_id = create_snapshot(region=region, description=description, - image=image) + image=image, tags=tags) client.get_waiter('snapshot_completed').wait(SnapshotIds=[snapshot_id]) image = client.register_image(Architecture=architecture, BlockDeviceMappings=[{ @@ -72,6 +94,10 @@ def import_image(region, name, architecture, image, public, overwrite): }], EnaSupport=True, Name=description, + TagSpecifications=[{ + 'ResourceType': 'image', + 'Tags': tags, + }], RootDeviceName='/dev/sda1', SriovNetSupport='simple', VirtualizationType='hvm') @@ -94,10 +120,14 @@ def launch_link(region, image_id): parser = argparse.ArgumentParser(description="Import AWS EC2 image (AMI)") parser.add_argument('--name', '-n', help="Image name") +parser.add_argument('--family', '-f', + help="Image family name") parser.add_argument('--public', '-p', action='store_true', help="Make image public") parser.add_argument('--overwrite', action='store_true', help="Overwrite any existing image with same name") +parser.add_argument('--retain', type=int, metavar='NUM', + help="Retain at most <NUM> old images") parser.add_argument('--region', '-r', action='append', help="AWS region(s)") parser.add_argument('--wiki', '-w', metavar='FILE', @@ -108,9 +138,13 @@ args = parser.parse_args() # Detect CPU architectures architectures = {image: detect_architecture(image) for image in args.image} +# Use default family name if none specified +if not args.family: + args.family = 'iPXE' + # Use default name if none specified if not args.name: - args.name = 'iPXE (%s)' % date.today().strftime('%Y-%m-%d') + args.name = '%s (%s)' % (args.family, date.today().strftime('%Y-%m-%d')) # Use all regions if none specified if not args.region: @@ -123,10 +157,12 @@ with ThreadPoolExecutor(max_workers=len(imports)) as executor: futures = {executor.submit(import_image, region=region, name=args.name, + family=args.family, architecture=architectures[image], image=image, public=args.public, - overwrite=args.overwrite): (region, image) + overwrite=args.overwrite, + retain=args.retain): (region, image) for region, image in imports} results = {futures[future]: future.result() for future in as_completed(futures)} diff --git a/contrib/crypto/cmsdetach b/contrib/crypto/cmsdetach new file mode 100755 index 0000000..0075009 --- /dev/null +++ b/contrib/crypto/cmsdetach @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 + +"""Detach CMS encrypted data. + +Detach encrypted data from a CMS envelopedData or authEnvelopedData +message into a separate file. +""" + +import argparse + +import asn1 + +# Parse command-line arguments +# +parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, +) +parser.add_argument("-d", "--data", metavar="FILE", + help="Write detached data (without envelope) to FILE") +parser.add_argument("-e", "--envelope", metavar="FILE", + help="Write envelope (without data) to FILE") +parser.add_argument("-o", "--overwrite", action="store_true", + help="Overwrite output files") +parser.add_argument("file", help="Input envelope file") +args = parser.parse_args() +if args.data is None and args.envelope is None: + parser.error("at least one of --data and --envelope is required") +outmode = "wb" if args.overwrite else "xb" + +# Create decoder +# +decoder = asn1.Decoder() +with open(args.file, mode="rb") as fh: + decoder.start(fh.read()) + +# Create encoder +# +encoder = asn1.Encoder() +encoder.start() + +# Detach encrypted data +# +data = None +datastack = [ + asn1.Numbers.Sequence, 0, asn1.Numbers.Sequence, asn1.Numbers.Sequence +] +stack = [] +while stack or not decoder.eof(): + if decoder.eof(): + encoder.leave() + decoder.leave() + stack.pop() + else: + tag = decoder.peek() + if tag.typ == asn1.Types.Constructed: + encoder.enter(nr=tag.nr, cls=tag.cls) + decoder.enter() + stack.append(tag.nr) + else: + (tag, value) = decoder.read() + if stack == datastack and tag.nr == 0: + data = value + else: + encoder.write(value, nr=tag.nr, cls=tag.cls) +envelope = encoder.output() +if data is None: + parser.error("Input file does not contain any encrypted data") + +# Write envelope (without data), if applicable +# +if args.envelope: + with open(args.envelope, mode=outmode) as fh: + fh.write(envelope) + +# Write data (without envelope), if applicable +# +if args.data: + with open(args.data, mode=outmode) as fh: + fh.write(data) diff --git a/contrib/rom-o-matic/README b/contrib/rom-o-matic/README deleted file mode 100644 index b68cf77..0000000 --- a/contrib/rom-o-matic/README +++ /dev/null @@ -1,62 +0,0 @@ -ROM-o-matic web interface for building iPXE ROMs ------------------------------------------------- - -This web application generates iPXE images and sends them to a web -browser. - -Available as part of the iPXE source code distribution, which can be -downlaoded from http://etherboot.org/ - -Author: Marty Connor <mdc@etherboot.org> -License: GPLv2 -Support: http://etherboot.org/mailman/listinfo/ipxe - Please send support questions to the iPXE mailing list - -System Requirements -------------------- -- Apache web server -- PHP 4+ -- Tools required to build iPXE installed on the server - - gcc, mtools, syslinux, perl, etc. - -Setup ------ -As distributed, it is expected that the rom-o-matic source code -directory is in the contrib directory of a iPXE source distribution. - -The easiest way to do this is to simply put a iPXE source distribution -in a web server accessible directory. - -If this is not the case, you will need to either edit the file - - "globals.php" - -or create a file called - - "local-config.php" - -containing the following lines: - -<?php -$src_dir = "../../src"; -?> - -Then change the line beginning "$src_dir = " to the path of your iPXE -source code tree. - -To make build times shorter, before you run rom-o-matic for the first time -you should cd to the ipxe "src" directory and enter the following -commands: - - $ make - $ make bin/NIC - -This will pro-compile most object files and will make your rom-o-matic -builds much faster. - -Running rom-o-matic from a web browser --------------------------------------- -Enter a URL like: - - http://example.com/ipxe-1.x.x/contrib/rom-o-matic - diff --git a/contrib/rom-o-matic/bottom.php b/contrib/rom-o-matic/bottom.php deleted file mode 100644 index 9ba8e31..0000000 --- a/contrib/rom-o-matic/bottom.php +++ /dev/null @@ -1,62 +0,0 @@ -<?php - -/** - * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>. - * Copyright (C) 2009 Entity Cyber, Inc. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -?> -<hr> -<h4> -Resources: -</h4> -<ul> - <li> - Source code for iPXE images is available at - <a href="http://www.ipxe.org/download" target="_blank"> - http://www.ipxe.org/download</a> - <br><br> - </li> - <li> - For general information about using iPXE, please visit the - <a href="http://www.ipxe.org/" target="_blank"> - iPXE Project Home Page</a> - <br><br> - </li> - <li> - For Email-based support for iPXE please join - <a href="http://www.ipxe.org/contact" target="_blank"> - iPXE Project mailing lists.</a> - <br><br> - </li> - <li> - For real-time online iPXE support via IRC please visit the - <a href="irc://irc.freenode.net/%23ipxe"> #ipxe channel - of irc.freenode.net</a>. - <br><br> - </li> -</ul> -<hr> - <font size="-1"> - <br> - Please email <a href="mailto:<?php echo "${webmaster_email}" ?>"><?php echo "${webmaster_email}"?></a> - with questions or comments about this website. - </font> - <br><br> -<hr> -</body> -</html> diff --git a/contrib/rom-o-matic/build.php b/contrib/rom-o-matic/build.php deleted file mode 100644 index b2b5bb4..0000000 --- a/contrib/rom-o-matic/build.php +++ /dev/null @@ -1,311 +0,0 @@ -<?php // -*- Mode: PHP; -*- - -/** - * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>. - * Copyright (C) 2009 Entity Cyber, Inc. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -// Get utility functions and set globals -require_once "utils.php"; - -// Make sure at least $A (action) was supplied -if ( ! isset ( $_POST['A'] ) ) { - - // Present user with form to customize build options - require_once "customize-flags.php"; - - exit (); - -// If user chose "Customize" option on form -} else if ( $_POST['A'] == "Customize" ) { - - // Present user with form to customize build options - require_once "customize-flags.php"; - - exit (); - -// The following conditional includes all other cases except "Get Image" -// particularly the explicit ($A == "Start Over") case -} else if ( $_POST['A'] != "Get Image" ) { - - // Note that this method of redirections discards all the - // configuration flags, which is intentional in this case. - - $dest = curDirURL (); - header ( "Location: $dest" ); - - // This next "echo" should normally not be seen, because - // the "header" statement above should cause immediate - // redirection but just in case... - - echo "Try this link: <a href=\"$dest\">$dest</a>"; - - exit (); -} - -// OK, we're going to try to use whatever options have been set -// to build an image. - -// Make sure at least $nic was supplied -if ( ! isset ( $_POST['nic'] ) ) { - die ( "No NIC supplied!" ); -} -if ( isset ( $nics[$_POST['nic']] ) ) { - $nic = $nics[$_POST['nic']]; -} else { - die ( "Invalid NIC \"${_POST['nic']}\" supplied!" ); -} - -// Fetch flags -$flags = get_flags (); - -// Get requested format -$ofmt = isset ( $_POST['ofmt'] ) ? $_POST['ofmt'] : ""; -$fmt_extension = isset ( $ofmts[$ofmt] ) ? $ofmts[$ofmt] : 'dsk'; - -// Handle some special cases - -$pci_vendor_code = ""; -$pci_device_code = ""; - -if ( $nic == 'undionly' && $fmt_extension == "pxe" ) { - - // undionly.pxe can't work because it unloads the PXE stack - // that it needs to communicate with, so we set the extension - // to .kpxe, which has a chance of working. The extension - // .kkpxe is another option. - - $fmt_extension = "kpxe"; - -} else if ( $fmt_extension == "rom" ) { - - if ( ! isset ( $_POST['pci_vendor_code'] ) - || ! isset ( $_POST['pci_device_code'] ) ) { - die ( "rom output format selected but PCI code(s) missing!" ); - } - - $pci_vendor_code = $_POST['pci_vendor_code']; - $pci_device_code = $_POST['pci_device_code']; - - if ( $pci_vendor_code == "" - || $pci_device_code == "" ) { - die ( "rom output format selected but PCI code(s) missing!" ); - } - - // Try to be forgiving of 0xAAAA format - if ( strtolower ( substr ( $pci_vendor_code, 0, 2 ) ) == "0x" - && strlen ( $pci_vendor_code ) == 6 ) { - $pci_vendor_code = substr ( $pci_vendor_code, 2, 4 ); - } - if ( strtolower ( substr ( $pci_device_code, 0, 2 ) ) == "0x" - && strlen ( $pci_device_code ) == 6 ) { - $pci_device_code = substr ( $pci_device_code, 2, 4 ); - } - - // concatenate the pci codes to get the $nic part of the - // Make target - $pci_codes = strtolower ( $pci_vendor_code . $pci_device_code ); - - $nic = $pci_codes; - if ( ! isset ( $roms[$pci_codes] ) ) { - die ( "Sorry, no network driver supports PCI codes<br>" - . "${_POST['pci_vendor_code']}:" - . "${_POST['pci_device_code']}" ); - } -} else if ( $fmt_extension != "rom" - && ( $pci_vendor_code != "" || $pci_device_code != "" ) ) { - die ( "'$fmt_extension' format was selected but PCI IDs were" - . " also entered.<br>Did you mean to select 'rom' output format" - . " instead?" ); -} - -/** - * remove temporary build directory - * - * @return bool true if removal is successful, false otherwise - */ -function rm_build_dir () -{ - global $build_dir; - global $keep_build_dir; - - if ( $keep_build_dir !== true ) { - rm_file_or_dir ( $build_dir ); - } -} - -// Arrange for the build directory to always be removed on exit. -$build_dir = ""; -$keep_build_dir = false; -register_shutdown_function ( 'rm_build_dir' ); - -// Make temporary copy of src directory -$build_dir = mktempcopy ( "$src_dir", "/tmp", "MDCROM" ); -$config_dir = $build_dir . "/config"; - -// Write config files with supplied flags -write_ipxe_config_files ( $config_dir, $flags ); - -// Handle a possible embedded script -$emb_script_cmd = ""; -$embedded_script = isset ( $_POST['embedded_script'] ) ? $_POST['embedded_script'] : ""; -if ( $embedded_script != "" ) { - $emb_script_path = "$build_dir" . "/script0.ipxe"; - - if ( substr ( $embedded_script, 0, 5 ) != "#!ipxe" ) { - $embedded_script = "#!ipxe\n" . $embedded_script; - } - - // iPXE 0.9.7 doesn't like '\r\n" in the shebang... - $embedded_script = str_replace ( "\r\n", "\n", $embedded_script ); - - write_file_from_string ( $emb_script_path, $embedded_script ); - $emb_script_cmd = "EMBEDDED_IMAGE=${emb_script_path}"; -} - -// Make the requested image. $status is set to 0 on success -$make_target = "bin/${nic}.${fmt_extension}"; -$gitversion = exec('git describe --always --abbrev=1 --match "" 2>/dev/null'); -if ($gitversion) { - $gitversion = "GITVERSION=$gitversion"; -} - -$make_cmd = "make -C '$build_dir' '$make_target' $gitversion $emb_script_cmd 2>&1"; - -exec ( $make_cmd, $maketxt, $status ); - -// Uncomment the following section for debugging - -/** - -echo "<h2>build.php:</h2>"; -echo "<h3>Begin debugging output</h3>"; - -//echo "<h3>\$_POST variables</h3>"; -//echo "<pre>"; var_dump ( $_POST ); echo "</pre>"; - -echo "<h3>Build options:</h3>"; -echo "<strong>Build directory is:</strong> $build_dir" . "<br><br>"; -echo "\$_POST['ofmt'] = " . "\"${_POST['ofmt']}\"" . "<br>"; -echo "\$_POST['nic'] = " . "\"${_POST['nic']}\"" . "<br>"; -echo "\$_POST['pci_vendor_code'] = " . "\"${_POST['pci_vendor_code']}\"" . "<br>"; -echo "\$_POST['pci_device_code'] = " . "\"${_POST['pci_device_code']}\"" . "<br>"; - -echo "<h3>Flags:</h3>"; -show_flags ( $flags ); - -if ( $embedded_script != "" ) { - echo "<h3>Embedded script:</h3>"; - echo "<blockquote>"."<pre>"; - echo $embedded_script; - echo "</pre>"."</blockquote>"; -} - -echo "<h3>Make output:</h3>"; -echo "Make command: " . $make_cmd . "<br>"; -echo "Build status = <? echo $status ?>" . "<br>"; -echo "<blockquote>"."<pre>"; -echo htmlentities ( implode ("\n", $maketxt ) ); -echo "</pre>"."</blockquote>"; -// Uncomment the next line if you want to keep the -// build directory around for inspection after building. -$keep_build_dir = true; -die ( "<h3>End debugging output</h3>" ); - -**/ // End debugging section - -// Send ROM to browser (with extreme prejudice) - -if ( $status == 0 ) { - - $fp = fopen("${build_dir}/${make_target}", "rb" ); - if ( $fp > 0 ) { - - $len = filesize ( "${build_dir}/${make_target}" ); - if ( $len > 0 ) { - - $buf = fread ( $fp, $len ); - fclose ( $fp ); - - // Delete build directory as soon as it is not needed - rm_build_dir (); - - $output_filename = preg_replace('/[^a-z0-9\+\.\-]/i', '', "ipxe-${version}-${nic}.${fmt_extension}"); - - // Try to force IE to handle downloading right. - Header ( "Cache-control: private"); - Header ( "Content-Type: application/x-octet-stream; " . - "name=$output_filename"); - Header ( "Content-Disposition: attachment; " . - "Filename=$output_filename"); - Header ( "Content-Location: $output_filename"); - Header ( "Content-Length: $len"); - - echo $buf; - - exit (); - } - } -} - -/* - * If we reach this point, the build has failed, and we provide - * debugging information for a potential bug report - * - */ - -// Remove build directory -rm_build_dir (); - -// Announce failure if $status from make was non-zero -echo "<h2>Build failed. Status = " . $status . "</h2>"; -echo "<h2>build.php:</h2>"; -echo "<h3>Build options:</h3>"; -echo "<strong>Build directory is:</strong> $build_dir" . "<br><br>"; -echo "\$_POST['ofmt'] = " . "\"${_POST['ofmt']}\"" . "<br>"; -echo "\$_POST['nic'] = " . "\"${_POST['nic']}\"" . "<br>"; -echo "\$_POST['pci_vendor_code'] = " . "\"${_POST['pci_vendor_code']}\"" . "<br>"; -echo "\$_POST['pci_device_code'] = " . "\"${_POST['pci_device_code']}\"" . "<br>"; - -echo "<h3>Flags:</h3>"; -show_flags ( $flags ); - -if ( $embedded_script != "" ) { - echo "<h3>Embedded script:</h3>"; - echo "<blockquote>"."<pre>"; - echo $embedded_script; - echo "</pre>"."</blockquote>"; -} - -echo "<h3>Make output:</h3>"; -echo "Make command: " . $make_cmd . "<br>"; -echo "<blockquote>"."<pre>"; -echo htmlentities ( implode ("\n", $maketxt ) ); -echo "</pre>"."</blockquote>"; - -echo "Please let us know that this happened, and paste the above output into your email message.<br>"; - -include_once $bottom_inc; - -// For emacs: -// Local variables: -// c-basic-offset: 4 -// c-indent-level: 4 -// tab-width: 4 -// End: - -?> diff --git a/contrib/rom-o-matic/customize-flags.php b/contrib/rom-o-matic/customize-flags.php deleted file mode 100644 index e283921..0000000 --- a/contrib/rom-o-matic/customize-flags.php +++ /dev/null @@ -1,69 +0,0 @@ -<?php // -*- Mode: PHP; -*- - -/** - * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>. - * Copyright (C) 2009 Entity Cyber, Inc. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -// Get utility functions and set globals -require_once "utils.php"; - -// Prepare settable compile options for presentation to user -$flags = default_flags (); - -$build = "<input type=\"submit\" name=\"A\" value=\"Get Image\">"; -$restart = "<input type=\"submit\" name=\"A\" value=\"Start Over\">"; - -// Begin html output -include_once $top_inc; - -?> - -<form action="build.php" method=POST> - <input type="hidden" name="version" value = "<?php echo $version ?>"> - <input type="hidden" name="use_flags" value="1"> - <h3> - Make changes below and press <?php echo $build ?> to create an image, <br> - Or press <?php echo $restart ?> to return to the main page. - </h3> - <hr> - <ul> - <?php require ( "directions.php" ); ?> - </ul> - <hr> - <?php echo_flags( $flags ); ?> - <hr> - <h3>Embedded Script:</h3> - <?php echo textarea ( "embedded_script", "", "10", "50" ); ?> - <br><br> - <hr> - <center><table width="35%"><tr> - <td align="left"> <?php echo $build; ?> </td> - <td align="right"> <?php echo $restart ?></td> - </tr></table></center> -</form> - -<?php include_once $bottom_inc; ?> -<? -// For emacs: -// -// Local variables: -// c-basic-offset: 4 -// c-indent-level: 4 -// tab-width: 4 -// End: -?> diff --git a/contrib/rom-o-matic/directions.php b/contrib/rom-o-matic/directions.php deleted file mode 100644 index 540121e..0000000 --- a/contrib/rom-o-matic/directions.php +++ /dev/null @@ -1,63 +0,0 @@ -<?php - -/** - * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>. - * Copyright (C) 2009 Entity Cyber, Inc. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -?> - <li> - Choose an output format: <?php echo keys_menubox ( "ofmt", $ofmts, - isset ( $_POST['ofmt'] ) ? $_POST['ofmt'] : "") ?> - <br><br> - </li> - <li> - Choose a NIC type: <?php echo keys_menubox ( "nic", $nics, - isset ( $_POST['nic'] ) ? $_POST['nic'] : "" ) ?> - <br><br> - </li> - <li> - <strong>( optional — for binary ROM image format only )</strong> <br><br> - If you choose <em>Binary ROM image</em> as your output format, you must<br> - enter <strong>4 hex digits</strong> below for - <em>PCI VENDOR CODE</em> and <em>PCI DEVICE CODE</em> <br> - that match the NIC device for which you are making this image.<br><br> - Information on how to determine NIC PCI IDs may be found - <a href="http://www.ipxe.org/howto/romburning" - target="_blank">here</a>. - <br><br> - PCI VENDOR CODE: <?php echo textbox ( "pci_vendor_code", - isset ( $_POST['pci_vendor_code'] ) ? $_POST['pci_vendor_code'] - : "", 6 ); ?> - - PCI DEVICE CODE: <?php echo textbox ( "pci_device_code", - isset ( $_POST['pci_device_code'] ) ? $_POST['pci_device_code'] - : "", 6 ); ?> - <h4>Please note for ROM images:</h4> - <ul> - <li> - If you enter PCI IDs, we will attempt to determine the correct<br> - driver to support them, and will ignore any NIC type entered - above.<br><br> - </li> - <li> - iPXE does not support all possible PCI IDs for supported - NICs. - <br><br> - </li> - </ul> - </li> diff --git a/contrib/rom-o-matic/doc/AUTOBOOT_CMD.html b/contrib/rom-o-matic/doc/AUTOBOOT_CMD.html deleted file mode 100644 index 444c5e6..0000000 --- a/contrib/rom-o-matic/doc/AUTOBOOT_CMD.html +++ /dev/null @@ -1 +0,0 @@ -Automatic booting diff --git a/contrib/rom-o-matic/doc/BANNER_TIMEOUT.html b/contrib/rom-o-matic/doc/BANNER_TIMEOUT.html deleted file mode 100644 index e135897..0000000 --- a/contrib/rom-o-matic/doc/BANNER_TIMEOUT.html +++ /dev/null @@ -1 +0,0 @@ -Tenths of a second for which the shell banner should appear diff --git a/contrib/rom-o-matic/doc/COMCONSOLE.html b/contrib/rom-o-matic/doc/COMCONSOLE.html deleted file mode 100644 index e7036c0..0000000 --- a/contrib/rom-o-matic/doc/COMCONSOLE.html +++ /dev/null @@ -1,3 +0,0 @@ -Serial Console I/O port address. Common addresses are:<br> -COM1 => 0x3f8, COM2 => 0x2f8, COM3 => 0x3e8, COM4 => 0x2e8 - diff --git a/contrib/rom-o-matic/doc/COMDATA.html b/contrib/rom-o-matic/doc/COMDATA.html deleted file mode 100644 index a27e275..0000000 --- a/contrib/rom-o-matic/doc/COMDATA.html +++ /dev/null @@ -1 +0,0 @@ -Serial Console Data bits diff --git a/contrib/rom-o-matic/doc/COMPARITY.html b/contrib/rom-o-matic/doc/COMPARITY.html deleted file mode 100644 index 14f3595..0000000 --- a/contrib/rom-o-matic/doc/COMPARITY.html +++ /dev/null @@ -1 +0,0 @@ -Serial Console Parity: 0=None, 1=Odd, 2=Even diff --git a/contrib/rom-o-matic/doc/COMPRESERVE.html b/contrib/rom-o-matic/doc/COMPRESERVE.html deleted file mode 100644 index 6e41a10..0000000 --- a/contrib/rom-o-matic/doc/COMPRESERVE.html +++ /dev/null @@ -1 +0,0 @@ -Keep settings from a previous user of the serial port
\ No newline at end of file diff --git a/contrib/rom-o-matic/doc/COMSPEED.html b/contrib/rom-o-matic/doc/COMSPEED.html deleted file mode 100644 index 32b6859..0000000 --- a/contrib/rom-o-matic/doc/COMSPEED.html +++ /dev/null @@ -1 +0,0 @@ -Serial Console Baud rate diff --git a/contrib/rom-o-matic/doc/COMSTOP.html b/contrib/rom-o-matic/doc/COMSTOP.html deleted file mode 100644 index ae3fd24..0000000 --- a/contrib/rom-o-matic/doc/COMSTOP.html +++ /dev/null @@ -1 +0,0 @@ -Serial Console Stop bits diff --git a/contrib/rom-o-matic/doc/CONFIG_CMD.html b/contrib/rom-o-matic/doc/CONFIG_CMD.html deleted file mode 100644 index 1256c06..0000000 --- a/contrib/rom-o-matic/doc/CONFIG_CMD.html +++ /dev/null @@ -1 +0,0 @@ -Option configuration console diff --git a/contrib/rom-o-matic/doc/CONSOLE_PC_BIOS.html b/contrib/rom-o-matic/doc/CONSOLE_PC_BIOS.html deleted file mode 100644 index 144eea3..0000000 --- a/contrib/rom-o-matic/doc/CONSOLE_PC_BIOS.html +++ /dev/null @@ -1 +0,0 @@ -Enable Default BIOS console diff --git a/contrib/rom-o-matic/doc/CONSOLE_SERIAL.html b/contrib/rom-o-matic/doc/CONSOLE_SERIAL.html deleted file mode 100644 index f35e2ff..0000000 --- a/contrib/rom-o-matic/doc/CONSOLE_SERIAL.html +++ /dev/null @@ -1 +0,0 @@ -Enable Serial port console diff --git a/contrib/rom-o-matic/doc/CRYPTO_80211_WEP.html b/contrib/rom-o-matic/doc/CRYPTO_80211_WEP.html deleted file mode 100644 index 26fdf8a..0000000 --- a/contrib/rom-o-matic/doc/CRYPTO_80211_WEP.html +++ /dev/null @@ -1 +0,0 @@ -Wireless WEP encryption support diff --git a/contrib/rom-o-matic/doc/CRYPTO_80211_WPA.html b/contrib/rom-o-matic/doc/CRYPTO_80211_WPA.html deleted file mode 100644 index b218a1e..0000000 --- a/contrib/rom-o-matic/doc/CRYPTO_80211_WPA.html +++ /dev/null @@ -1 +0,0 @@ -Wireless WPA encryption support diff --git a/contrib/rom-o-matic/doc/CRYPTO_80211_WPA2.html b/contrib/rom-o-matic/doc/CRYPTO_80211_WPA2.html deleted file mode 100644 index 947597d..0000000 --- a/contrib/rom-o-matic/doc/CRYPTO_80211_WPA2.html +++ /dev/null @@ -1 +0,0 @@ -Wireless WPA2 encryption support diff --git a/contrib/rom-o-matic/doc/DHCP_CMD.html b/contrib/rom-o-matic/doc/DHCP_CMD.html deleted file mode 100644 index a0c31c7..0000000 --- a/contrib/rom-o-matic/doc/DHCP_CMD.html +++ /dev/null @@ -1 +0,0 @@ -DHCP management commands diff --git a/contrib/rom-o-matic/doc/DNS_RESOLVER.html b/contrib/rom-o-matic/doc/DNS_RESOLVER.html deleted file mode 100644 index 1029b9c..0000000 --- a/contrib/rom-o-matic/doc/DNS_RESOLVER.html +++ /dev/null @@ -1 +0,0 @@ -DNS resolver diff --git a/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_FTP.html b/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_FTP.html deleted file mode 100644 index 7686d5d..0000000 --- a/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_FTP.html +++ /dev/null @@ -1 +0,0 @@ -File Transfer Protocol diff --git a/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_HTTP.html b/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_HTTP.html deleted file mode 100644 index c28d888..0000000 --- a/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_HTTP.html +++ /dev/null @@ -1 +0,0 @@ -Hypertext Transfer Protocol diff --git a/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_TFTP.html b/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_TFTP.html deleted file mode 100644 index f2b31b1..0000000 --- a/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_TFTP.html +++ /dev/null @@ -1 +0,0 @@ -Trivial File Transfer Protocol diff --git a/contrib/rom-o-matic/doc/IFMGMT_CMD.html b/contrib/rom-o-matic/doc/IFMGMT_CMD.html deleted file mode 100644 index 0e2b2a5..0000000 --- a/contrib/rom-o-matic/doc/IFMGMT_CMD.html +++ /dev/null @@ -1 +0,0 @@ -Interface management commands diff --git a/contrib/rom-o-matic/doc/IMAGE_BZIMAGE.html b/contrib/rom-o-matic/doc/IMAGE_BZIMAGE.html deleted file mode 100644 index d85e5d0..0000000 --- a/contrib/rom-o-matic/doc/IMAGE_BZIMAGE.html +++ /dev/null @@ -1 +0,0 @@ -Linux bzImage image support diff --git a/contrib/rom-o-matic/doc/IMAGE_CMD.html b/contrib/rom-o-matic/doc/IMAGE_CMD.html deleted file mode 100644 index 6f5acb5..0000000 --- a/contrib/rom-o-matic/doc/IMAGE_CMD.html +++ /dev/null @@ -1 +0,0 @@ -Image management commands diff --git a/contrib/rom-o-matic/doc/IMAGE_ELF.html b/contrib/rom-o-matic/doc/IMAGE_ELF.html deleted file mode 100644 index 5e39e8b..0000000 --- a/contrib/rom-o-matic/doc/IMAGE_ELF.html +++ /dev/null @@ -1 +0,0 @@ -ELF image support diff --git a/contrib/rom-o-matic/doc/IMAGE_MULTIBOOT.html b/contrib/rom-o-matic/doc/IMAGE_MULTIBOOT.html deleted file mode 100644 index 6a092a2..0000000 --- a/contrib/rom-o-matic/doc/IMAGE_MULTIBOOT.html +++ /dev/null @@ -1 +0,0 @@ -MultiBoot image support diff --git a/contrib/rom-o-matic/doc/IMAGE_NBI.html b/contrib/rom-o-matic/doc/IMAGE_NBI.html deleted file mode 100644 index eb78e03..0000000 --- a/contrib/rom-o-matic/doc/IMAGE_NBI.html +++ /dev/null @@ -1 +0,0 @@ -NBI image support diff --git a/contrib/rom-o-matic/doc/IMAGE_PXE.html b/contrib/rom-o-matic/doc/IMAGE_PXE.html deleted file mode 100644 index bdca384..0000000 --- a/contrib/rom-o-matic/doc/IMAGE_PXE.html +++ /dev/null @@ -1 +0,0 @@ -PXE image support diff --git a/contrib/rom-o-matic/doc/IMAGE_SCRIPT.html b/contrib/rom-o-matic/doc/IMAGE_SCRIPT.html deleted file mode 100644 index 8741672..0000000 --- a/contrib/rom-o-matic/doc/IMAGE_SCRIPT.html +++ /dev/null @@ -1 +0,0 @@ -iPXE script image support diff --git a/contrib/rom-o-matic/doc/IWMGMT_CMD.html b/contrib/rom-o-matic/doc/IWMGMT_CMD.html deleted file mode 100644 index 0d5bd4a..0000000 --- a/contrib/rom-o-matic/doc/IWMGMT_CMD.html +++ /dev/null @@ -1 +0,0 @@ -Wireless interface management commands diff --git a/contrib/rom-o-matic/doc/NMB_RESOLVER.html b/contrib/rom-o-matic/doc/NMB_RESOLVER.html deleted file mode 100644 index a0bdc17..0000000 --- a/contrib/rom-o-matic/doc/NMB_RESOLVER.html +++ /dev/null @@ -1 +0,0 @@ -NMB resolver diff --git a/contrib/rom-o-matic/doc/NVO_CMD.html b/contrib/rom-o-matic/doc/NVO_CMD.html deleted file mode 100644 index 5346f3f..0000000 --- a/contrib/rom-o-matic/doc/NVO_CMD.html +++ /dev/null @@ -1 +0,0 @@ -Non-volatile option storage commands diff --git a/contrib/rom-o-matic/doc/ROUTE_CMD.html b/contrib/rom-o-matic/doc/ROUTE_CMD.html deleted file mode 100644 index 8114c26..0000000 --- a/contrib/rom-o-matic/doc/ROUTE_CMD.html +++ /dev/null @@ -1 +0,0 @@ -Routing table management commands diff --git a/contrib/rom-o-matic/doc/SANBOOT_CMD.html b/contrib/rom-o-matic/doc/SANBOOT_CMD.html deleted file mode 100644 index 2e9d840..0000000 --- a/contrib/rom-o-matic/doc/SANBOOT_CMD.html +++ /dev/null @@ -1 +0,0 @@ -SAN boot commands diff --git a/contrib/rom-o-matic/flag-table.php b/contrib/rom-o-matic/flag-table.php deleted file mode 100644 index fe81c80..0000000 --- a/contrib/rom-o-matic/flag-table.php +++ /dev/null @@ -1,531 +0,0 @@ -<?php // -*- Mode: PHP; -*- - -/** - * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>. - * Copyright (C) 2009 Entity Cyber, Inc. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -$ofmts = array - ( "Floppy bootable image (.dsk)" => "dsk", - "SYSLINUX-based bootable floppy image (.sdsk)" => "sdsk", - "ISO bootable image (.iso)" => "iso", - "ISO bootable image with legacy floppy emulation (.liso)" => "liso", - "Linux kernel (SYSLINUX/GRUB/LILO) loadable image (.lkrn)" => "lkrn", - "USB Keychain disk image (.usb)" => "usb", - "ROM binary (flashable) image (.rom)" => "rom", - "ROM binary (flashable) for problem PMM BIOSES (.hrom)" => "hrom", - "PXE bootstrap loader image [Unload PXE stack] (.pxe)" => "pxe", - "PXE bootstrap loader keep [Keep PXE stack method 1] (.kpxe)" => "kpxe", - "PXE bootstrap loader keep [Keep PXE stack method 2] (.kkpxe)" => "kkpxe", - ); - -$flag_table = array ( - - // Begin General Options: - - "HDR_MISC_OPTIONS" - => array ( - "flag" => "HDR_MISC_OPTIONS", - "hide_from_user" => "yes", // Hide even the header - "type" => "header", - "label" => "Miscellaneous Options" - ), - - "PRODUCT_NAME" - => array ( - "flag" => "PRODUCT_NAME", - "hide_from_user" => "yes", - "type" => "string", - "value" => "", - "cfgsec" => "general" - ), - - "PRODUCT_SHORT_NAME" - => array ( - "flag" => "PRODUCT_SHORT_NAME", - "hide_from_user" => "yes", - "type" => "string", - "value" => "iPXE", - "cfgsec" => "general" - ), - - // End General Options: - - // Begin Console Options: - - "HDR_CONSOLE_OPTIONS" - => array ( - "flag" => "HDR_CONSOLE_OPTIONS", - "type" => "header", - "label" => "Console Options" - ), - - "CONSOLE_PCBIOS" - => array ( - "flag" => "CONSOLE_PCBIOS", - "type" => "on/off", - "value" => "on", - "cfgsec" => "console" - ), - - "CONSOLE_SERIAL" - => array ( - "flag" => "CONSOLE_SERIAL", - "type" => "on/off", - "value" => "off", - "cfgsec" => "console" - ), - - "BANNER_TIMEOUT" - => array ( - "flag" => "BANNER_TIMEOUT", - "type" => "integer", - "value" => "20", - "cfgsec" => "general" - ), - - "KEYBOARD_MAP" - => array ( - "flag" => "KEYBOARD_MAP", - "type" => "choice", - "options" => array("al","az","bg","by","cf","cz","de","dk","es","et","fi","fr", - "gr","hu","il","it","lt","mk","mt","nl","no","pl","pt","ro","ru","sg","sr", - "th","ua","uk","us","wo"), - "value" => "us", - "cfgsec" => "console" - ), - - "LOG_LEVEL" - => array ( - "flag" => "LOG_LEVEL", - "type" => "choice", - "options" => array("LOG_NONE","LOG_EMERG","LOG_ALERT","LOG_CRIT","LOG_ERR", - "LOG_WARNING","LOG_NOTICE","LOG_INFO","LOG_DEBUG","LOG_ALL"), - "value" => "LOG_NONE", - "cfgsec" => "console" - ), - - // End Console Options - - // Begin Network Protocol Options: - - "HDR_NETWORK_PROTOCOL_OPTIONS" - => array ( - "flag" => "HDR_NETWORK_PROTOCOL_OPTIONS", - "hide_from_user" => "yes", // Hide even the header - "type" => "header", - "label" => "Network Protocol Options" - ), - - "NET_PROTO_IPV4" - => array ( - "flag" => "NET_PROTO_IPV4", - "type" => "on/off", - "value" => "on", - "hide_from_user" => "yes", - "cfgsec" => "general" - ), - - // End Network Protocol Options - - // Begin Serial Port configuration - - "HDR_SERIAL_PORT_OPTIONS" - => array ( - "flag" => "HDR_SERIAL_PORT_OPTIONS", - "type" => "header", - "label" => "Serial Port Options" - ), - - "COMCONSOLE" - => array ( - "flag" => "COMCONSOLE", - "type" => "integer-hex", // e.g. 0x378 - "value" => "0x3F8", - "cfgsec" => "serial" - ), - - "COMPRESERVE" - => array ( - "flag" => "COMPRESERVE", - "type" => "on/off", - "value" => "off", - "cfgsec" => "serial" - ), - - "COMSPEED" - => array ( - "flag" => "COMSPEED", - "type" => "integer", - "value" => "115200", - "cfgsec" => "serial" - ), - - "COMDATA" - => array ( - "flag" => "COMDATA", - "type" => "integer", - "value" => "8", - "cfgsec" => "serial" - ), - - "COMPARITY" - => array ( - "flag" => "COMPARITY", - "type" => "integer", - "value" => "0", - "cfgsec" => "serial" - ), - - "COMSTOP" - => array ( - "flag" => "COMSTOP", - "type" => "integer", - "value" => "1", - "cfgsec" => "serial" - ), - - // End Serial Options - - // Begin Download Protocols - - "HDR_DOWNLOAD_PROTOCOLS" - => array ( - "flag" => "HDR_DOWNLOAD_PROTOCOLS", - "type" => "header", - "label" => "Download Protocols" - ), - - "DOWNLOAD_PROTO_TFTP" - => array ( - "flag" => "DOWNLOAD_PROTO_TFTP", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "DOWNLOAD_PROTO_HTTP" - => array ( - "flag" => "DOWNLOAD_PROTO_HTTP", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "DOWNLOAD_PROTO_HTTPS" - => array ( - "flag" => "DOWNLOAD_PROTO_HTTPS", - "type" => "on/off", - "value" => "off", - "cfgsec" => "general" - ), - - "DOWNLOAD_PROTO_FTP" - => array ( - "flag" => "DOWNLOAD_PROTO_FTP", - "type" => "on/off", - "value" => "off", - "cfgsec" => "general" - ), - - // End Download Protocols - - // Begin SAN boot protocols - - "HDR_SANBOOT_PROTOCOLS" - => array ( - "flag" => "HDR_SANBOOT_PROTOCOLS", - "type" => "header", - "label" => "SAN Boot Protocols" - ), - - "SANBOOT_PROTO_ISCSI" - => array ( - "flag" => "SANBOOT_PROTO_ISCSI", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "SANBOOT_PROTO_AOE" - => array ( - "flag" => "SANBOOT_PROTO_AOE", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - // End SAN boot protocols - - // Begin Name resolution modules - - "HDR_NAME_RESOLUTION_MODULES" - => array ( - "flag" => "HDR_NAME_RESOLUTION_MODULES", - "type" => "header", - "label" => "Name Resolution Modules" - ), - - "DNS_RESOLVER" - => array ( - "flag" => "DNS_RESOLVER", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "NMB_RESOLVER" - => array ( - "flag" => "NMB_RESOLVER", - "type" => "on/off", - "value" => "off", - "hide_from_user" => "yes", - "cfgsec" => "general" - ), - - // End Name resolution modules - - // Begin Image types - - "HDR_IMAGE_TYPES" - => array ( - "flag" => "HDR_IMAGE_TYPES", - "type" => "header", - "label" => "Image Types", - ), - - "IMAGE_ELF" - => array ( - "flag" => "IMAGE_ELF", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "IMAGE_NBI" - => array ( - "flag" => "IMAGE_NBI", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "IMAGE_MULTIBOOT" - => array ( - "flag" => "IMAGE_MULTIBOOT", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "IMAGE_PXE" - => array ( - "flag" => "IMAGE_PXE", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "IMAGE_SCRIPT" - => array ( - "flag" => "IMAGE_SCRIPT", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "IMAGE_BZIMAGE" - => array ( - "flag" => "IMAGE_BZIMAGE", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "IMAGE_COMBOOT" - => array ( - "flag" => "IMAGE_COMBOOT", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - // End Image types - - // Begin Command-line commands to include - - "HDR_COMMAND_LINE_OPTIONS" - => array ( - "flag" => "HDR_COMMAND_LINE_OPTIONS", - "type" => "header", - "label" => "Command Line Options", - ), - - "AUTOBOOT_CMD" - => array ( - "flag" => "AUTOBOOT_CMD", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "NVO_CMD" - => array ( - "flag" => "NVO_CMD", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "CONFIG_CMD" - => array ( - "flag" => "CONFIG_CMD", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "IFMGMT_CMD" - => array ( - "flag" => "IFMGMT_CMD", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "IWMGMT_CMD" - => array ( - "flag" => "IWMGMT_CMD", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "ROUTE_CMD" - => array ( - "flag" => "ROUTE_CMD", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "IMAGE_CMD" - => array ( - "flag" => "IMAGE_CMD", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "DHCP_CMD" - => array ( - "flag" => "DHCP_CMD", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "SANBOOT_CMD" - => array ( - "flag" => "SANBOOT_CMD", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "LOGIN_CMD" - => array ( - "flag" => "LOGIN_CMD", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "TIME_CMD" - => array ( - "flag" => "TIME_CMD", - "type" => "on/off", - "value" => "off", - "cfgsec" => "general" - ), - - "DIGEST_CMD" - => array ( - "flag" => "DIGEST_CMD", - "type" => "on/off", - "value" => "off", - "cfgsec" => "general" - ), - - // End Command-line commands to include - - // Begin Wireless options - - "HDR_WIRELESS_OPTIONS" - => array ( - "flag" => "HDR_WIRELESS_OPTIONS", - "type" => "header", - "label" => "Wireless Interface Options", - ), - - "CRYPTO_80211_WEP" - => array ( - "flag" => "CRYPTO_80211_WEP", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "CRYPTO_80211_WPA" - => array ( - "flag" => "CRYPTO_80211_WPA", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - "CRYPTO_80211_WPA2" - => array ( - "flag" => "CRYPTO_80211_WPA2", - "type" => "on/off", - "value" => "on", - "cfgsec" => "general" - ), - - // End Wireless options - - // Obscure options required to compile - "NETDEV_DISCARD_RATE" - => array ( - "flag" => "NETDEV_DISCARD_RATE", - "type" => "integer", - "value" => "0", - "cfgsec" => "general", - "hide_from_user" => true - ) - - // End Obscure options -); - -// For emacs: -// Local variables: -// c-basic-offset: 4 -// c-indent-level: 4 -// tab-width: 4 -// End: - -?> diff --git a/contrib/rom-o-matic/globals.php b/contrib/rom-o-matic/globals.php deleted file mode 100644 index 822e4bc..0000000 --- a/contrib/rom-o-matic/globals.php +++ /dev/null @@ -1,51 +0,0 @@ -<?php // -*- Mode: PHP; -*- - -/** - * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>. - * Copyright (C) 2009 Entity Cyber, Inc. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -// Directory containing iPXE source code tree -$src_dir = "../../src"; - -// Compute iPXE version based on source tree -exec ( "make -C '$src_dir' version 2>&1", $make_output, $status ); -$version = ( $status == 0 && count ( $make_output ) > 1 ) - ? trim ( $make_output[count ( $make_output ) - 2] ) - : ""; - -// Email address of person responsible for this website -$webmaster_email = "webmaster@example.com"; - -// Files that header and footer text -$top_inc = "top.php"; -$bottom_inc = "bottom.php"; - -// Descriptive strings -$header_title = "ROM-o-matic for iPXE $version"; -$html_tagline = "ROM-o-matic dynamically generates iPXE images"; -$html_title = "ROM-o-matic for iPXE $version"; -$description = "a dynamic iPXE image generator"; - -// For emacs: -// Local variables: -// c-basic-offset: 4 -// c-indent-level: 4 -// tab-width: 4 -// End: - -?> diff --git a/contrib/rom-o-matic/index.php b/contrib/rom-o-matic/index.php deleted file mode 100644 index 26585c9..0000000 --- a/contrib/rom-o-matic/index.php +++ /dev/null @@ -1,47 +0,0 @@ -<?php // -*- Mode: PHP; -*- - -/** - * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>. - * Copyright (C) 2009 Entity Cyber, Inc. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -// Get utility functions and set globals -require_once "utils.php"; - -// Begin html output -include_once $top_inc; - -?> -<form action="build.php" method=POST> - <input type="hidden" name="version" value = "<?php echo $version ?>"> - <h3>To create an image:</h3> - <ol> - <?php require ( "directions.php" ); ?> - <li> - Generate and download an image: - <input type="submit" name="A" value="Get Image"> - <br><br> - </li> - <li> - (optional) Customize image configuration options: - <input type="submit" name="A" value="Customize"> - <br><br> - </li> - </ol> -</form> - -<?php include_once $bottom_inc ?> diff --git a/contrib/rom-o-matic/top.php b/contrib/rom-o-matic/top.php deleted file mode 100644 index 42a8e2d..0000000 --- a/contrib/rom-o-matic/top.php +++ /dev/null @@ -1,41 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> - -<?php - -/** - * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>. - * Copyright (C) 2009 Entity Cyber, Inc. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -?> - -<html> -<head> - <link rev="made" href="mailto:<?php echo "${webmaster_email}" ?>"> - <meta name="keywords" content="rom, etherboot, ipxe, open source, rom-o-matic.net"> - <title><?php echo $header_title ?></title> - <meta name="description" content="<?php echo $description ?>"> -</head> -<h1> -<?php echo "$html_title" ?> -</h1> -<hr> -<h2> -<?php echo "$html_tagline" ?> -</h2> -</form> -<hr> diff --git a/contrib/rom-o-matic/utils.php b/contrib/rom-o-matic/utils.php deleted file mode 100644 index e0e62f4..0000000 --- a/contrib/rom-o-matic/utils.php +++ /dev/null @@ -1,684 +0,0 @@ -<?php // -*- Mode: PHP; -*- - -/** - * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>. - * Copyright (C) 2009 Entity Cyber, Inc. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -// Include table of user-configurable iPXE options -require_once "flag-table.php"; - -// Include user-shadowable globals -require_once "globals.php"; - -// Allow user to shadow globals -if ( is_file ( 'local-config.php' ) ) { - include_once "local-config.php"; -} - -//// -// General utility functions -//// - -/** - * Remove undesirable characters from a given string - * - * Certain characters have the potential to be used for - * malicious purposes by web-based attackers. This routine - * filters out such characters. - * - * @param string $s supplied string - * - * @return string returned string with unwanted characters - * removed - */ -function cleanstring ( $s ) -{ - $len = strlen ( $s ); - if ( $len > 80 ) { - $s = substr ( $s, 0, 80 ); - } - - $s = trim ( $s ); - $pos = 0; - $result = ""; - - while ( $pos < $len ) { - $ltr = ord ( ucfirst ( $s[$pos] ) ); - if ( ( $ltr >= ord ( "A" ) ) && ( $ltr <= ord ( "Z" ) ) || - ( $ltr >= ord ( "0" ) ) && ( $ltr <= ord ( "9" ) ) || - ( $ltr == ord ( "." ) ) && ( strlen ( $result ) > 0 ) || - ( $ltr == ord ( "_" ) ) || - ( $ltr == ord ( "+" ) ) || - ( $ltr == ord ( ":" ) ) || - ( $ltr == ord ( "/" ) ) || - ( $ltr == ord ( "-" ) ) ) { - $result .= $s[$pos]; - } - $pos++; - } - return $result; -} - -/** - * Return URL of the currently running script, minus the filename - * - * @return string the URL of the currently running script, minus the filename - */ -function curDirURL () -{ - $dir = dirname ( $_SERVER['PHP_SELF'] ); - - if ( $dir == "." || $dir == "/" ) { - $dir = ""; - } - - $isHTTPS = ( isset ( $_SERVER["HTTPS"] ) && $_SERVER["HTTPS"] == "on" ); - $port = ( isset($_SERVER["SERVER_PORT"] ) && - ( ( !$isHTTPS && $_SERVER["SERVER_PORT"] != "80" ) || - ( $isHTTPS && $_SERVER["SERVER_PORT"] != "443" ) ) ); - - $port = ( $port ) ? ':' . $_SERVER["SERVER_PORT"] : ''; - - $dest = ( $isHTTPS ? 'https://' : 'http://' ) . - $_SERVER["SERVER_NAME"] . $dir . "/"; - - return $dest; -} - -/** - * Extract NIC families and associated ROM PCI IDs from the src/bin/NIC file. - * - * $src_dir must contain the path of the iPXE src directory for this build - * - * @return array[0] array $new_nics - * @return array[1] array $roms - */ -function parse_nic_file () -{ - global $src_dir; - - $fd = fopen ( "$src_dir/bin/NIC", "r" ); - if ( ! $fd ) { - die ( "Missing src/bin/NIC file. 'make bin/NIC'" ); - } - - $nics = array (); - $roms = array (); - $nic = ""; - - while ( !feof ( $fd ) ) { - - $line = trim ( fgets ( $fd, 200 ) ); - - $first_eight_chars = substr ( $line, 0, 8 ); - settype ( $first_eight_chars, "string" ); - - if ( strpos ( $first_eight_chars, "family" ) === 0 ) { - - // get pathname of NIC driver - #list ( $dummy, $nic ) = split( "[ \t]+", $line ); - list ( $dummy, $nic ) = explode("\t", $line); - settype ( $nic, "string" ); - - // extract filename name of driver from pathname - $nic = substr ( $nic, strrpos ( $nic, "/" ) + 1, - strlen ( $nic ) - strrpos ( $nic, "/" ) + 1 ); - - $nics[$nic] = $nic; - - // For each ISA NIC, there can only be one ROM variant - $roms[$nic] = $nic; - } - - // If the first 8 digits of the line are hex digits - // add this rom to the current nic family. - - if ( ( strlen ( $first_eight_chars ) == 8 ) - && ( ctype_xdigit ( $first_eight_chars ) ) - && ( $nic != "" ) ) { - - $roms[$first_eight_chars] = $nic; - } - } - fclose ( $fd ); - - // put most NICs in nice alpha order for menu - ksort ( $nics ); - - // add special cases to the top - - $new_nics = array ( "all-drivers" => "ipxe", - "undionly" => "undionly", - "undi" => "undi", - ); - - foreach ( $nics as $key => $value ) { - // skip the undi driver - if ( $key != "undi" ) { - $new_nics[$key] = $value; - } - } - - return array ( $new_nics, $roms ); -} - -//// -// HTML form utility functions -//// - -/** - * Return html code to create hidden form input fields - * - * @param string $flag name of form variable to set - * @param string $value value to give form variable - * - * @return string html code for given hidden form input field - */ -function hidden ( $flag, $value ) -{ - $value = htmlentities ( $value ); - return "<input type=\"hidden\" value=\"$value\" name=\"$flag\"></input>"; -} - -/** - * Return html code to create checkbox form input fields - * - * @param string $flag name of form variable to set - * @param string $value "on" means box should be checked - * - * @return string html code for given hidden form input field - */ -function checkbox ( $flag, $value ) -{ - return "<input type=\"checkbox\" value=\"on\" name=\"$flag\"" . - ($value == "on" ? " checked>" : ">" ); -} - -/** - * Return html code to create text form input fields - * - * @param string $flag name of form variable to set - * @param string $value initial contents of field - * @param string $size size in characters of text box - * - * @return string html code for given text input field - */ -function textbox ( $flag, $value, $size ) -{ - $value = htmlentities ( $value ); - return "<input type=\"text\" size=\"$size\" value=\"$value\" name=\"$flag\">"; -} - -/** - * Return html code to create textarea form fields - * - * @param string $flag name of form variable to set - * @param string $value initial contents of textarea - * @param string $rows height of text area in rows - * @param string $cols width of text area in columns - * - * @return string html code for given textarea input field - */ -function textarea ( $flag, $value, $rows, $cols ) -{ - $value = htmlentities ( $value ); - return "<textarea name=\"$flag\" rows=\"$rows\" cols=\"$cols\">" - . $value . "</textarea>"; -} - -/** - * Return html code to create select (menu) form fields - * - * Use array of strings as menu choices - * - * @param string $flag name of form variable to set - * @param array $options array of strings representing choices - * @param string $value value of choice to select in menu - * - * @return string html code for given select (menu) input field - */ -function menubox ( $name, $options, $value ) -{ - $s="<select name=\"$name\">"; - - foreach ( $options as $ignore => $option ) { - if ( !$value ) $value = $option; - $s .= "<option" . ( $option == $value ? " selected>" : ">" ) . - htmlentities ( $option ) . "</option>"; - } - return $s . "</select>"; -} - -/** - * Return html code to create select (menu) form fields - * - * Use indices of array of strings as menu choices rather than - * the values pointed to by the indicies. - * - * @param string $flag name of form variable to set - * @param array $options array of strings representing choices - * @param string $value value of choice to select in menu - * - * @return string html code for given select (menu) input field - */ -function keys_menubox ( $name, $options, $value ) -{ - $s="<select name=\"$name\">"; - - foreach ( $options as $option => $ignore ) { - if ( !$value ) $value = $option; - $s .= "<option" . ( $option == $value ? " selected>" : ">" ) . - htmlentities ( $option ) . "</option>"; - } - return $s . "</select>"; -} - -//// -// Flag (compile option) handling functions -//// - -/** - * Return default compile options (flags) - * - * Initial compile options are in a global called $flag_table. - * Create and return an array containing the ones we want. - * - * @return array default compile options (flags) - */ -function default_flags () -{ - global $flag_table; - - $flags = array (); - - foreach ( $flag_table as $key => $props ) { - - $flag = $props["flag"]; - $type = $props["type"]; - - // Fields like headers have no "value" property - if ( isset ( $props["value"] ) ) { - $flags[$flag] = $props["value"]; - } - } - return $flags; -} - -/** - * Return combination of default and user compile options (flags) - * - * Initial compile options are in a global called $flag_table. - * Compile options may have been changed via form input. We return - * an array with either the default value of each option or a user - * supplied value from form input. - * - * @return array combined default and user supplied compile options (flags) - */ -function get_flags () -{ - global $flag_table; - - $flags = default_flags (); - - if ( ! isset ( $_POST["use_flags"] ) ) - return $flags; - - foreach ( $flag_table as $key => $props ) { - - $flag = $props["flag"]; - $type = $props["type"]; - - if ( isset ( $_POST["$flag"] ) ) { - $flags[$flag] = $_POST["$flag"]; - if ( $type == "integer-hex" ) { - if ( strtolower ( substr ( $flags[$flag], 0, 2 ) ) != "0x" ) { - $flags[$flag] = "0x" . $flags[$flag]; - } - } - } else if ( $type == "on/off" ) { - // Unchecked checkboxes don't pass any POST value - // so we must check for them specially. At this - // point we know that there is no $_POST value set - // for this option. If it is a checkbox, this means - // it is unchecked, so record that in $flags so we - // can later generate an #undef for this option. - $flags[$flag] = "off"; - } - } - return $flags; -} - -/** - * Output given value in appropriate format for iPXE config file - * - * iPXE config/*.h files use C pre-processor syntax. Output the given - * compile option in a format appropriate to its type - * - * @param string $key index into $flag_table for given compile option - * @param string $value value we wish to set compile option to - * - * @return string code to set compile option to given value - */ -function pprint_flag ( $key, $value ) -{ - global $flag_table; - - // Determine type of given compile option (flag) - $type = $flag_table[$key]["type"]; - $s = ""; - - if ( $type == "on/off" && $value == "on" ) { - $s = "#define $key"; - } else if ( $type == "on/off" && $value != "on" ) { - $s = "#undef $key"; - } else if ( $type == "string" ) { - $s = ( "#define $key \"" . cleanstring ( $value ) . "\"" ); - } else if ($type == "qstring" ) { - $s = ( "#define $key \\\"" . cleanstring ( $value ) . "\\\"" ); - } else { - $s = "#define $key " . cleanstring ( $value ); - } - - return $s; -} - -/** - * Output html code to display all compile options as a table - * - * @param array $flags array of compile options - * - * @return void - */ -function echo_flags ( $flags ) -{ - global $flag_table; - - echo "<table>\n"; - - foreach ( $flag_table as $key => $props ) { - - // Hide parameters from users that should not be changed. - $hide_from_user = isset ( $props["hide_from_user"] ) ? $props["hide_from_user"] : "no"; - - $flag = $props["flag"]; - $type = $props["type"]; - - $value = isset ( $flags[$flag] ) ? $flags[$flag] : ''; - - if ( $hide_from_user == "yes" ) { - - // Hidden flags cannot not be set by the user. We use hidden form - // fields to keep them at their default values. - if ( $type != "header" ) { - echo hidden ( $flag, $value ); - } - - } else { - - // Flag (iPXE compile option) should be displayed to user - - if ( $type == "header" ) { - - $label = $props["label"]; - echo "<td colspan=2><hr><h3>$label</h3><hr></td>"; - - } else if ($type == "on/off" ) { - - echo "<td>", checkbox ( $flag, $value ), "</td><td><strong>$flag</strong></td>"; - - } else { // don't display checkbox for non-on/off flags - - echo "<td> </td><td><strong>$flag: </strong>"; - - if ($type == "choice" ) { - $options = $props["options"]; - echo menubox($flag, $options, $value); - - } else { - - echo textbox($flag, $value, ($type == "integer" || - $type == "integer-hex" - ? 7 : 25)); - } - echo "</td>"; - } - echo "</tr>\n"; - - if ( $type != "header" ) { - echo "<tr><td> </td>"; - echo "<td>\n"; - if ( is_file ( "doc/$flag.html" ) ) { - include_once "doc/$flag.html"; - } - echo "\n</td></tr>\n"; - } - } - } - echo "</table>"; -} - -/** - * Return an array of configuration sections used in all compile options - * - * $flag_table, the global list of compile options contains a 'cfgsec' - * property for each flag we are interested in. We return a list of - * all the unique cfgsec options we find in $flag_table. - * - * @return array an array of strings representing all unique cfgsec values - * found in $flag_table - */ -function get_flag_cfgsecs () -{ - global $flag_table; - $cfgsecs = array (); - - foreach ( $flag_table as $key => $props ) { - if ( isset ( $props['cfgsec'] ) ) { - $cfgsec = $props["cfgsec"]; - $cfgsecs[$cfgsec] = $cfgsec; - } - } - return $cfgsecs; -} - -//// -// File and directory handling functions -//// - -/** - * Create a copy of a given source directory to a given destination - * - * Since we are going to modify the source directory, we create a copy - * of the directory with a unique name in the given destination directory. - * We supply a prefix for the tempnam call to prepend to the random filename - * it generates. - * - * @param string $src source directory - * @param string $dst destination directory - * @param string $prefix string to append to directory created - * - * @return string absolute path to destination directory - */ -function mktempcopy ( $src, $dst, $prefix ) -{ - if ( $src[0] != "/" ) { - $src = dirname ( $_SERVER['SCRIPT_FILENAME'] ) . "/" . $src; - } - - // Create a file in the given destination directory with a unique name - $dir = tempnam ( $dst, $prefix ); - - // Delete the file just created, since it would interfere with the copy we - // are about to do. We only care that the dir name we copy to is unique. - unlink ( $dir ); - - exec ( "/bin/cp -a '$src' '$dir' 2>&1", $cpytxt, $status ); - - if ( $status != 0 ) { - die ( "src directory copy failed!" ); - } - return $dir; -} - -/** - * Write iPXE config files based on value of given flags - * - * iPXE compile options are stored in src/config/*.h . - * We write out a config file for each set of options. - * - * @param string $config_dir directory to write .h files to - * @param array $flags array of compile options for this build - * - * @return void - */ -function write_ipxe_config_files ( $config_dir, $flags ) -{ - global $flag_table; - - $cfgsecs = get_flag_cfgsecs (); - - foreach ( $cfgsecs as $cfgsec ) { - - $fname = $config_dir . "/" . $cfgsec . ".h"; - - $fp = fopen ( $fname, "wb" ); - if ( $fp <= 0 ) { - die ( "Unable to open $fname file for output!" ); - } - - $ifdef_secname = "CONFIG_" . strtoupper ( $cfgsec ) . "_H"; - - fwrite ( $fp, "#ifndef ${ifdef_secname}\n" ); - fwrite ( $fp, "#define ${ifdef_secname}\n" ); - fwrite ( $fp, "#include <config/defaults.h>\n" ); - - foreach ( $flags as $key => $value ) { - // When the flag matches this section name, write it out - if ( $flag_table[$key]["cfgsec"] == $cfgsec ) { - fwrite ( $fp, pprint_flag ( $key, $value ) . "\n" ); - } - } - fwrite ( $fp, "#endif /* ${ifdef_secname} */\n" ); - fclose ( $fp ); - } -} - -/** - * Output a string to a file - * - * Output a given string to a given pathname. The file will be created if - * necessary, and the string will replace the file's contents in all cases. - * - * @param string $fname pathname of file to output string to - * @param string $ftext text to output to file - * - * @return void - */ -function write_file_from_string ( $fname, $ftext ) -{ - $fp = fopen ( $fname, "wb" ); - if ( ! $fp ) { - die ( "Unable to open $fname file for output!" ); - } - fwrite ( $fp, $ftext ); - fclose ( $fp ); -} - -/** - * Delete a file or recursively delete a directory tree - * - * @param string $file_or_dir_name name of file or directory to delete - * @return bool Returns TRUE on success, FALSE on failure - */ -function rm_file_or_dir ( $file_or_dir_name ) -{ - if ( ! file_exists ( $file_or_dir_name ) ) { - return false; - } - - if ( is_file ( $file_or_dir_name ) || is_link ( $file_or_dir_name ) ) { - return unlink ( $file_or_dir_name ); - } - - $dir = dir ( $file_or_dir_name ); - while ( ( $dir_entry = $dir->read () ) !== false ) { - - if ( $dir_entry == '.' || $dir_entry == '..') { - continue; - } - rm_file_or_dir ( $file_or_dir_name . '/' . $dir_entry ); - } - $dir->close(); - - return rmdir ( $file_or_dir_name ); -} - -//// -// Debugging functions -//// - -/** - * Emit html code to display given array of compile options (flags) - * - * @param array $flags array of compile options for this build - * - * @return void - */ -function show_flags ( $flags ) -{ - echo ( "\$flags contains " . count ( $flags ) . " elements:" . "<br>" ); - - foreach ( $flags as $key => $flag ) { - echo ( "\$flags[" . $key . "]=" . "\"$flag\"" . "<br>" ); - } -} - -/** - * Emit HTML code to display default array of compile options (flags) - * - * $flag_table contains default compile options and properties. This - * routine outputs HTML code to display all properties of $flag_table. - * - * @return void - */ -function dump_flag_table () -{ - global $flag_table; - - echo ( "\$flag_table contains " . count ( $flag_table ) . " elements:" . "<br>" ); - - foreach ( $flag_table as $key => $props ) { - print ( "flag_table[" . $key . "] = " . "<br>" ); - - foreach ( $props as $key2 => $props2 ) { - print ( " " . $key2 . " = " . $props2 . "<br>" ); - } - } -} - -// Parse src/bin/NIC file -list ( $nics, $roms ) = parse_nic_file (); - -// For emacs: -// Local variables: -// c-basic-offset: 4 -// c-indent-level: 4 -// tab-width: 4 -// End: - -?> diff --git a/src/Makefile b/src/Makefile index bc82cc6..9571962 100644 --- a/src/Makefile +++ b/src/Makefile @@ -77,6 +77,7 @@ SRCDIRS += drivers/net/efi SRCDIRS += drivers/net/tg3 SRCDIRS += drivers/net/bnxt SRCDIRS += drivers/net/sfc +SRCDIRS += drivers/net/marvell SRCDIRS += drivers/block SRCDIRS += drivers/nvs SRCDIRS += drivers/bitbash diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping index d13cb36..5d9c039 100644 --- a/src/Makefile.housekeeping +++ b/src/Makefile.housekeeping @@ -366,11 +366,6 @@ MAKEDEPS += arch/$(ARCH)/Makefile include arch/$(ARCH)/Makefile endif -# Include architecture-specific include path -ifdef ARCH -INCDIRS += arch/$(ARCH)/include -endif - ############################################################################### # # Especially ugly workarounds diff --git a/src/arch/arm/Makefile b/src/arch/arm/Makefile index b6509dd..f827ed4 100644 --- a/src/arch/arm/Makefile +++ b/src/arch/arm/Makefile @@ -3,9 +3,9 @@ ASM_TCHAR := % ASM_TCHAR_OPS := %% -# Include common ARM headers +# Include ARM-specific headers # -INCDIRS += arch/arm/include +INCDIRS := arch/$(ARCH)/include arch/arm/include $(INCDIRS) # ARM-specific directories containing source files # diff --git a/src/arch/arm/include/bits/acpi.h b/src/arch/arm/include/bits/acpi.h deleted file mode 100644 index f9f2f00..0000000 --- a/src/arch/arm/include/bits/acpi.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_ACPI_H -#define _BITS_ACPI_H - -/** @file - * - * ARM-specific ACPI API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_ACPI_H */ diff --git a/src/arch/arm/include/bits/hyperv.h b/src/arch/arm/include/bits/hyperv.h deleted file mode 100644 index f0e0c87..0000000 --- a/src/arch/arm/include/bits/hyperv.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_HYPERV_H -#define _BITS_HYPERV_H - -/** @file - * - * Hyper-V interface - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_HYPERV_H */ diff --git a/src/arch/arm/include/bits/iomap.h b/src/arch/arm/include/bits/iomap.h deleted file mode 100644 index ae953c4..0000000 --- a/src/arch/arm/include/bits/iomap.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_IOMAP_H -#define _BITS_IOMAP_H - -/** @file - * - * ARM-specific I/O mapping API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_IOMAP_H */ diff --git a/src/arch/arm/include/bits/mp.h b/src/arch/arm/include/bits/mp.h deleted file mode 100644 index e7d4c0c..0000000 --- a/src/arch/arm/include/bits/mp.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_MP_H -#define _BITS_MP_H - -/** @file - * - * ARM-specific multiprocessor API implementation - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_MP_H */ diff --git a/src/arch/arm/include/bits/pci_io.h b/src/arch/arm/include/bits/pci_io.h deleted file mode 100644 index 91f507a..0000000 --- a/src/arch/arm/include/bits/pci_io.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_PCI_IO_H -#define _BITS_PCI_IO_H - -/** @file - * - * ARM PCI I/O API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_PCI_IO_H */ diff --git a/src/arch/arm/include/bits/reboot.h b/src/arch/arm/include/bits/reboot.h deleted file mode 100644 index 88c5025..0000000 --- a/src/arch/arm/include/bits/reboot.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_REBOOT_H -#define _BITS_REBOOT_H - -/** @file - * - * ARM-specific reboot API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_REBOOT_H */ diff --git a/src/arch/arm/include/bits/sanboot.h b/src/arch/arm/include/bits/sanboot.h deleted file mode 100644 index abd4c79..0000000 --- a/src/arch/arm/include/bits/sanboot.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_SANBOOT_H -#define _BITS_SANBOOT_H - -/** @file - * - * ARM-specific sanboot API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_SANBOOT_H */ diff --git a/src/arch/arm/include/bits/smbios.h b/src/arch/arm/include/bits/smbios.h deleted file mode 100644 index d942181..0000000 --- a/src/arch/arm/include/bits/smbios.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_SMBIOS_H -#define _BITS_SMBIOS_H - -/** @file - * - * ARM-specific SMBIOS API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_SMBIOS_H */ diff --git a/src/arch/arm/include/bits/time.h b/src/arch/arm/include/bits/time.h deleted file mode 100644 index 724d8b9..0000000 --- a/src/arch/arm/include/bits/time.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_TIME_H -#define _BITS_TIME_H - -/** @file - * - * ARM-specific time API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_TIME_H */ diff --git a/src/arch/arm/include/bits/uaccess.h b/src/arch/arm/include/bits/uaccess.h deleted file mode 100644 index 87f1150..0000000 --- a/src/arch/arm/include/bits/uaccess.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_UACCESS_H -#define _BITS_UACCESS_H - -/** @file - * - * ARM-specific user access API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_UACCESS_H */ diff --git a/src/arch/arm/include/bits/uart.h b/src/arch/arm/include/bits/uart.h deleted file mode 100644 index 6f85975..0000000 --- a/src/arch/arm/include/bits/uart.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_UART_H -#define _BITS_UART_H - -/** @file - * - * 16550-compatible UART - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_UART_H */ diff --git a/src/arch/arm/include/bits/umalloc.h b/src/arch/arm/include/bits/umalloc.h deleted file mode 100644 index 27970d7..0000000 --- a/src/arch/arm/include/bits/umalloc.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_UMALLOC_H -#define _BITS_UMALLOC_H - -/** @file - * - * ARM-specific user memory allocation API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_UMALLOC_H */ diff --git a/src/arch/arm32/include/bits/tcpip.h b/src/arch/arm32/include/bits/tcpip.h deleted file mode 100644 index fc3c5b3..0000000 --- a/src/arch/arm32/include/bits/tcpip.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _BITS_TCPIP_H -#define _BITS_TCPIP_H - -/** @file - * - * Transport-network layer interface - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -static inline __attribute__ (( always_inline )) uint16_t -tcpip_continue_chksum ( uint16_t partial, const void *data, size_t len ) { - - /* Not yet optimised */ - return generic_tcpip_continue_chksum ( partial, data, len ); -} - -#endif /* _BITS_TCPIP_H */ diff --git a/src/arch/arm32/include/gdbmach.h b/src/arch/arm32/include/gdbmach.h deleted file mode 100644 index cd152ee..0000000 --- a/src/arch/arm32/include/gdbmach.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef GDBMACH_H -#define GDBMACH_H - -/** @file - * - * GDB architecture specifics - * - * This file declares functions for manipulating the machine state and - * debugging context. - * - */ - -#include <stdint.h> - -typedef unsigned long gdbreg_t; - -/* Register snapshot */ -enum { - /* Not yet implemented */ - GDBMACH_NREGS, -}; - -#define GDBMACH_SIZEOF_REGS ( GDBMACH_NREGS * sizeof ( gdbreg_t ) ) - -static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) { - /* Not yet implemented */ - ( void ) regs; - ( void ) pc; -} - -static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) { - /* Not yet implemented */ - ( void ) regs; - ( void ) step; -} - -static inline void gdbmach_breakpoint ( void ) { - /* Not yet implemented */ -} - -extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, - int enable ); -extern void gdbmach_init ( void ); - -#endif /* GDBMACH_H */ diff --git a/src/arch/arm64/include/gdbmach.h b/src/arch/arm64/include/gdbmach.h deleted file mode 100644 index cd152ee..0000000 --- a/src/arch/arm64/include/gdbmach.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef GDBMACH_H -#define GDBMACH_H - -/** @file - * - * GDB architecture specifics - * - * This file declares functions for manipulating the machine state and - * debugging context. - * - */ - -#include <stdint.h> - -typedef unsigned long gdbreg_t; - -/* Register snapshot */ -enum { - /* Not yet implemented */ - GDBMACH_NREGS, -}; - -#define GDBMACH_SIZEOF_REGS ( GDBMACH_NREGS * sizeof ( gdbreg_t ) ) - -static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) { - /* Not yet implemented */ - ( void ) regs; - ( void ) pc; -} - -static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) { - /* Not yet implemented */ - ( void ) regs; - ( void ) step; -} - -static inline void gdbmach_breakpoint ( void ) { - /* Not yet implemented */ -} - -extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, - int enable ); -extern void gdbmach_init ( void ); - -#endif /* GDBMACH_H */ diff --git a/src/arch/i386/include/gdbmach.h b/src/arch/i386/include/bits/gdbmach.h index 52cce78..52cce78 100644 --- a/src/arch/i386/include/gdbmach.h +++ b/src/arch/i386/include/bits/gdbmach.h diff --git a/src/arch/loong64/Makefile b/src/arch/loong64/Makefile index fd0bf13..90d0ec8 100644 --- a/src/arch/loong64/Makefile +++ b/src/arch/loong64/Makefile @@ -18,6 +18,9 @@ endif # EFI requires -fshort-wchar, and nothing else currently uses wchar_t CFLAGS += -fshort-wchar +# Include LoongArch64-specific headers +INCDIRS := arch/$(ARCH)/include $(INCDIRS) + # LoongArch64-specific directories containing source files SRCDIRS += arch/loong64/core SRCDIRS += arch/loong64/interface/efi diff --git a/src/arch/loong64/include/bits/acpi.h b/src/arch/loong64/include/bits/acpi.h deleted file mode 100644 index 83dd1df..0000000 --- a/src/arch/loong64/include/bits/acpi.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_ACPI_H -#define _BITS_ACPI_H - -/** @file - * - * LoongArch64-specific ACPI API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_ACPI_H */ diff --git a/src/arch/loong64/include/bits/hyperv.h b/src/arch/loong64/include/bits/hyperv.h deleted file mode 100644 index f0e0c87..0000000 --- a/src/arch/loong64/include/bits/hyperv.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_HYPERV_H -#define _BITS_HYPERV_H - -/** @file - * - * Hyper-V interface - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_HYPERV_H */ diff --git a/src/arch/loong64/include/bits/iomap.h b/src/arch/loong64/include/bits/iomap.h deleted file mode 100644 index 041171d..0000000 --- a/src/arch/loong64/include/bits/iomap.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_IOMAP_H -#define _BITS_IOMAP_H - -/** @file - * - * LoongArch64-specific I/O mapping API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_IOMAP_H */ diff --git a/src/arch/loong64/include/bits/mp.h b/src/arch/loong64/include/bits/mp.h deleted file mode 100644 index fef2fd5..0000000 --- a/src/arch/loong64/include/bits/mp.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_MP_H -#define _BITS_MP_H - -/** @file - * - * LoongArch64-specific multiprocessor API implementation - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_MP_H */ diff --git a/src/arch/loong64/include/bits/pci_io.h b/src/arch/loong64/include/bits/pci_io.h deleted file mode 100644 index fdc5141..0000000 --- a/src/arch/loong64/include/bits/pci_io.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_PCI_IO_H -#define _BITS_PCI_IO_H - -/** @file - * - * LoongArch64-specific PCI I/O API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_PCI_IO_H */ diff --git a/src/arch/loong64/include/bits/reboot.h b/src/arch/loong64/include/bits/reboot.h deleted file mode 100644 index 96a1eb1..0000000 --- a/src/arch/loong64/include/bits/reboot.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_REBOOT_H -#define _BITS_REBOOT_H - -/** @file - * - * LoongArch64-specific reboot API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_REBOOT_H */ diff --git a/src/arch/loong64/include/bits/sanboot.h b/src/arch/loong64/include/bits/sanboot.h deleted file mode 100644 index f9205e2..0000000 --- a/src/arch/loong64/include/bits/sanboot.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_SANBOOT_H -#define _BITS_SANBOOT_H - -/** @file - * - * LoongArch64-specific sanboot API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_SANBOOT_H */ diff --git a/src/arch/loong64/include/bits/smbios.h b/src/arch/loong64/include/bits/smbios.h deleted file mode 100644 index 6c87db4..0000000 --- a/src/arch/loong64/include/bits/smbios.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_SMBIOS_H -#define _BITS_SMBIOS_H - -/** @file - * - * LoongArch64-specific SMBIOS API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_SMBIOS_H */ diff --git a/src/arch/loong64/include/bits/tcpip.h b/src/arch/loong64/include/bits/tcpip.h deleted file mode 100644 index fc3c5b3..0000000 --- a/src/arch/loong64/include/bits/tcpip.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _BITS_TCPIP_H -#define _BITS_TCPIP_H - -/** @file - * - * Transport-network layer interface - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -static inline __attribute__ (( always_inline )) uint16_t -tcpip_continue_chksum ( uint16_t partial, const void *data, size_t len ) { - - /* Not yet optimised */ - return generic_tcpip_continue_chksum ( partial, data, len ); -} - -#endif /* _BITS_TCPIP_H */ diff --git a/src/arch/loong64/include/bits/time.h b/src/arch/loong64/include/bits/time.h deleted file mode 100644 index 4cd7485..0000000 --- a/src/arch/loong64/include/bits/time.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_TIME_H -#define _BITS_TIME_H - -/** @file - * - * LoongArch64-specific time API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_TIME_H */ diff --git a/src/arch/loong64/include/bits/uaccess.h b/src/arch/loong64/include/bits/uaccess.h deleted file mode 100644 index dddd9be..0000000 --- a/src/arch/loong64/include/bits/uaccess.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_UACCESS_H -#define _BITS_UACCESS_H - -/** @file - * - * LoongArch64-specific user access API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_UACCESS_H */ diff --git a/src/arch/loong64/include/bits/uart.h b/src/arch/loong64/include/bits/uart.h deleted file mode 100644 index 6f85975..0000000 --- a/src/arch/loong64/include/bits/uart.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_UART_H -#define _BITS_UART_H - -/** @file - * - * 16550-compatible UART - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_UART_H */ diff --git a/src/arch/loong64/include/bits/umalloc.h b/src/arch/loong64/include/bits/umalloc.h deleted file mode 100644 index f6978b8..0000000 --- a/src/arch/loong64/include/bits/umalloc.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_UMALLOC_H -#define _BITS_UMALLOC_H - -/** @file - * - * LoongArch64-specific user memory allocation API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_UMALLOC_H */ diff --git a/src/arch/x86/Makefile b/src/arch/x86/Makefile index ef80136..4a4d8ee 100644 --- a/src/arch/x86/Makefile +++ b/src/arch/x86/Makefile @@ -3,9 +3,9 @@ ASM_TCHAR := @ ASM_TCHAR_OPS := @ -# Include common x86 headers +# Include x86-specific headers # -INCDIRS += arch/x86/include +INCDIRS := arch/$(ARCH)/include arch/x86/include $(INCDIRS) # x86-specific directories containing source files # diff --git a/src/arch/x86/core/cpuid_settings.c b/src/arch/x86/core/cpuid_settings.c index 0b67ee9..9bc69f4 100644 --- a/src/arch/x86/core/cpuid_settings.c +++ b/src/arch/x86/core/cpuid_settings.c @@ -38,7 +38,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * * Bit 31 Extended function * Bits 30-24 (bit 22 = 1) Subfunction number - * (bit 22 = 0) Number of consecutive functions to call, minus one + * Bit 30 (bit 22 = 0) Hypervisor function + * Bits 29-24 (bit 22 = 0) Number of consecutive functions to call, minus one * Bit 23 Return result as little-endian (used for strings) * Bit 22 Interpret bits 30-24 as a subfunction number * Bits 21-18 Unused @@ -98,7 +99,7 @@ enum cpuid_flags { * @v tag Setting tag * @ret function Starting function number */ -#define CPUID_FUNCTION( tag ) ( (tag) & 0x800000ffUL ) +#define CPUID_FUNCTION( tag ) ( (tag) & 0xc00000ffUL ) /** * Extract subfunction number from CPUID setting tag @@ -109,6 +110,14 @@ enum cpuid_flags { #define CPUID_SUBFUNCTION( tag ) ( ( (tag) >> 24 ) & 0x7f ) /** + * Extract number of consecutive functions from CPUID setting tag + * + * @v tag Setting tag + * @ret num_functions Number of consecutive functions + */ +#define CPUID_NUM_FUNCTIONS( tag ) ( ( ( (tag) >> 24 ) & 0x3f ) + 1 ) + +/** * Extract register array from CPUID setting tag * * @v tag Setting tag @@ -165,12 +174,13 @@ static int cpuid_settings_fetch ( struct settings *settings, /* Call each function in turn */ function = CPUID_FUNCTION ( setting->tag ); - subfunction = CPUID_SUBFUNCTION ( setting->tag ); if ( setting->tag & CPUID_USE_SUBFUNCTION ) { + function &= ~CPUID_HYPERVISOR; + subfunction = CPUID_SUBFUNCTION ( setting->tag ); num_functions = 1; } else { - num_functions = ( subfunction + 1 ); subfunction = 0; + num_functions = CPUID_NUM_FUNCTIONS ( setting->tag ); } for ( ; num_functions-- ; function++ ) { diff --git a/src/arch/x86/core/gdbmach.c b/src/arch/x86/core/gdbmach.c index af6abfe..d4d187e 100644 --- a/src/arch/x86/core/gdbmach.c +++ b/src/arch/x86/core/gdbmach.c @@ -31,7 +31,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/uaccess.h> #include <ipxe/gdbstub.h> #include <librm.h> -#include <gdbmach.h> /** @file * diff --git a/src/arch/x86/core/pcidirect.c b/src/arch/x86/core/pcidirect.c index f4659a1..90d4623 100644 --- a/src/arch/x86/core/pcidirect.c +++ b/src/arch/x86/core/pcidirect.c @@ -45,6 +45,7 @@ void pcidirect_prepare ( struct pci_device *pci, int where ) { PCIDIRECT_CONFIG_ADDRESS ); } +PROVIDE_PCIAPI_INLINE ( direct, pci_can_probe ); PROVIDE_PCIAPI_INLINE ( direct, pci_discover ); PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_byte ); PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_word ); diff --git a/src/arch/x86/include/ipxe/pcibios.h b/src/arch/x86/include/ipxe/pcibios.h index 3caea1c..ef95856 100644 --- a/src/arch/x86/include/ipxe/pcibios.h +++ b/src/arch/x86/include/ipxe/pcibios.h @@ -33,6 +33,16 @@ extern int pcibios_write ( struct pci_device *pci, uint32_t command, uint32_t value ); /** + * Check if PCI bus probing is allowed + * + * @ret ok Bus probing is allowed + */ +static inline __always_inline int +PCIAPI_INLINE ( pcbios, pci_can_probe ) ( void ) { + return 1; +} + +/** * Read byte from PCI configuration space via PCI BIOS * * @v pci PCI device diff --git a/src/arch/x86/include/ipxe/pcicloud.h b/src/arch/x86/include/ipxe/pcicloud.h index 5226890..1feef56 100644 --- a/src/arch/x86/include/ipxe/pcicloud.h +++ b/src/arch/x86/include/ipxe/pcicloud.h @@ -15,4 +15,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define PCIAPI_PREFIX_cloud __cloud_ #endif +/** + * Check if PCI bus probing is allowed + * + * @ret ok Bus probing is allowed + */ +static inline __always_inline int +PCIAPI_INLINE ( cloud, pci_can_probe ) ( void ) { + return 1; +} + #endif /* _IPXE_PCICLOUD_H */ diff --git a/src/arch/x86/include/ipxe/pcidirect.h b/src/arch/x86/include/ipxe/pcidirect.h index 98c6a2b..999b527 100644 --- a/src/arch/x86/include/ipxe/pcidirect.h +++ b/src/arch/x86/include/ipxe/pcidirect.h @@ -26,6 +26,16 @@ struct pci_device; extern void pcidirect_prepare ( struct pci_device *pci, int where ); /** + * Check if PCI bus probing is allowed + * + * @ret ok Bus probing is allowed + */ +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_can_probe ) ( void ) { + return 1; +} + +/** * Find next PCI bus:dev.fn address range in system * * @v busdevfn Starting PCI bus:dev.fn address diff --git a/src/arch/x86/interface/pcbios/pcibios.c b/src/arch/x86/interface/pcbios/pcibios.c index 7b7a769..ebe40ba 100644 --- a/src/arch/x86/interface/pcbios/pcibios.c +++ b/src/arch/x86/interface/pcbios/pcibios.c @@ -120,6 +120,7 @@ int pcibios_write ( struct pci_device *pci, uint32_t command, uint32_t value ){ return ( status >> 8 ); } +PROVIDE_PCIAPI_INLINE ( pcbios, pci_can_probe ); PROVIDE_PCIAPI ( pcbios, pci_discover, pcibios_discover ); PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_byte ); PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_word ); diff --git a/src/arch/x86/interface/pcbios/pcicloud.c b/src/arch/x86/interface/pcbios/pcicloud.c index 98ba38b..f7d4a2d 100644 --- a/src/arch/x86/interface/pcbios/pcicloud.c +++ b/src/arch/x86/interface/pcbios/pcicloud.c @@ -148,6 +148,7 @@ static void * pcicloud_ioremap ( struct pci_device *pci, return pcicloud->pci_ioremap ( pci, bus_addr, len ); } +PROVIDE_PCIAPI_INLINE ( cloud, pci_can_probe ); PROVIDE_PCIAPI ( cloud, pci_discover, pcicloud_discover ); PROVIDE_PCIAPI ( cloud, pci_read_config_byte, pcicloud_read_config_byte ); PROVIDE_PCIAPI ( cloud, pci_read_config_word, pcicloud_read_config_word ); diff --git a/src/arch/x86_64/include/gdbmach.h b/src/arch/x86_64/include/bits/gdbmach.h index 367405f..367405f 100644 --- a/src/arch/x86_64/include/gdbmach.h +++ b/src/arch/x86_64/include/bits/gdbmach.h diff --git a/src/config/config.c b/src/config/config.c index 6bcd3c1..f532c1d 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -299,6 +299,9 @@ REQUIRE_OBJECT ( image_mem_cmd ); #ifdef SHIM_CMD REQUIRE_OBJECT ( shim_cmd ); #endif +#ifdef IMAGE_CRYPT_CMD +REQUIRE_OBJECT ( image_crypt_cmd ); +#endif /* * Drag in miscellaneous objects diff --git a/src/config/config_crypto.c b/src/config/config_crypto.c index 5211224..f118a97 100644 --- a/src/config/config_crypto.c +++ b/src/config/config_crypto.c @@ -88,6 +88,16 @@ REQUIRE_OBJECT ( oid_sha512_256 ); REQUIRE_OBJECT ( oid_x25519 ); #endif +/* AES-CBC */ +#if defined ( CRYPTO_CIPHER_AES_CBC ) +REQUIRE_OBJECT ( oid_aes_cbc ); +#endif + +/* AES-GCM */ +#if defined ( CRYPTO_CIPHER_AES_GCM ) +REQUIRE_OBJECT ( oid_aes_gcm ); +#endif + /* RSA and MD5 */ #if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_DIGEST_MD5 ) REQUIRE_OBJECT ( rsa_md5 ); diff --git a/src/config/general.h b/src/config/general.h index f936e87..b82e560 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -158,6 +158,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); //#define REBOOT_CMD /* Reboot command */ //#define POWEROFF_CMD /* Power off command */ //#define IMAGE_TRUST_CMD /* Image trust management commands */ +//#define IMAGE_CRYPT_CMD /* Image encryption management commands */ //#define PCI_CMD /* PCI commands */ //#define PARAM_CMD /* Request parameter commands */ //#define NEIGHBOUR_CMD /* Neighbour management commands */ diff --git a/src/core/archive.c b/src/core/archive.c index bb62c7e..3d3f00c 100644 --- a/src/core/archive.c +++ b/src/core/archive.c @@ -43,7 +43,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ int image_extract ( struct image *image, const char *name, struct image **extracted ) { - char *dot; int rc; /* Check that this image can be used to extract an archive image */ @@ -66,10 +65,8 @@ int image_extract ( struct image *image, const char *name, } /* Strip any archive or compression suffix from implicit name */ - if ( ( ! name ) && ( (*extracted)->name ) && - ( ( dot = strrchr ( (*extracted)->name, '.' ) ) != NULL ) ) { - *dot = '\0'; - } + if ( ! name ) + image_strip_suffix ( *extracted ); /* Try extracting archive image */ if ( ( rc = image->type->extract ( image, *extracted ) ) != 0 ) { diff --git a/src/core/gdbstub.c b/src/core/gdbstub.c index 8b57ddf..d668f45 100644 --- a/src/core/gdbstub.c +++ b/src/core/gdbstub.c @@ -36,7 +36,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ctype.h> #include <byteswap.h> #include <ipxe/gdbstub.h> -#include "gdbmach.h" enum { POSIX_EINVAL = 0x1c, /* used to report bad arguments to GDB */ diff --git a/src/core/image.c b/src/core/image.c index bf0e4f7..c69c05c 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -173,6 +173,25 @@ int image_set_name ( struct image *image, const char *name ) { } /** + * Strip dot suffix from image name, if present + * + * @v image Image + * @ret sep Position of old dot separator, or NULL + */ +char * image_strip_suffix ( struct image *image ) { + char *dot; + + /* Locate and strip suffix, if present */ + if ( image->name && + ( ( dot = strrchr ( image->name, '.' ) ) != NULL ) ) { + *dot = '\0'; + return dot; + } + + return NULL; +} + +/** * Set image command line * * @v image Image diff --git a/src/crypto/asn1.c b/src/crypto/asn1.c index dc9d1c5..aa57c6a 100644 --- a/src/crypto/asn1.c +++ b/src/crypto/asn1.c @@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <time.h> #include <ipxe/tables.h> #include <ipxe/image.h> +#include <ipxe/crypto.h> #include <ipxe/asn1.h> /** @file @@ -94,8 +95,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * object body (i.e. the first byte following the length byte(s)), and * the length of the object body (i.e. the number of bytes until the * following object tag, if any) is returned. + * + * If the expected type is not found, the object cursor will not be + * modified. If any other error occurs, the object cursor will be + * invalidated. */ -int asn1_start ( struct asn1_cursor *cursor, unsigned int type, size_t extra ) { +static int asn1_start ( struct asn1_cursor *cursor, unsigned int type, + size_t extra ) { unsigned int len_len; unsigned int len; @@ -103,6 +109,7 @@ int asn1_start ( struct asn1_cursor *cursor, unsigned int type, size_t extra ) { if ( cursor->len < 2 /* Tag byte and first length byte */ ) { if ( cursor->len ) DBGC ( cursor, "ASN1 %p too short\n", cursor ); + asn1_invalidate_cursor ( cursor ); return -EINVAL_ASN1_EMPTY; } @@ -127,6 +134,7 @@ int asn1_start ( struct asn1_cursor *cursor, unsigned int type, size_t extra ) { if ( cursor->len < len_len ) { DBGC ( cursor, "ASN1 %p bad length field length %d (max " "%zd)\n", cursor, len_len, cursor->len ); + asn1_invalidate_cursor ( cursor ); return -EINVAL_ASN1_LEN_LEN; } @@ -140,6 +148,7 @@ int asn1_start ( struct asn1_cursor *cursor, unsigned int type, size_t extra ) { if ( ( cursor->len + extra ) < len ) { DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n", cursor, len, ( cursor->len + extra ) ); + asn1_invalidate_cursor ( cursor ); return -EINVAL_ASN1_LEN; } @@ -147,33 +156,59 @@ int asn1_start ( struct asn1_cursor *cursor, unsigned int type, size_t extra ) { } /** - * Enter ASN.1 object + * Enter ASN.1 partial object * * @v cursor ASN.1 object cursor * @v type Expected type, or ASN1_ANY + * @v extra Additional length beyond partial object * @ret rc Return status code * - * The object cursor will be updated to point to the body of the - * current ASN.1 object. If any error occurs, the object cursor will - * be invalidated. + * The object cursor and additional length will be updated to point to + * the body of the current ASN.1 object. + * + * If any error occurs, the object cursor will be invalidated. */ -int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) { +int asn1_enter_partial ( struct asn1_cursor *cursor, unsigned int type, + size_t *extra ) { int len; - len = asn1_start ( cursor, type, 0 ); + /* Parse current object */ + len = asn1_start ( cursor, type, *extra ); if ( len < 0 ) { asn1_invalidate_cursor ( cursor ); return len; } - cursor->len = len; + /* Update cursor and additional length */ + if ( ( ( size_t ) len ) <= cursor->len ) + cursor->len = len; + assert ( ( len - cursor->len ) <= *extra ); + *extra = ( len - cursor->len ); + DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n", cursor, type, len ); - return 0; } /** + * Enter ASN.1 object + * + * @v cursor ASN.1 object cursor + * @v type Expected type, or ASN1_ANY + * @ret rc Return status code + * + * The object cursor will be updated to point to the body of the + * current ASN.1 object. + * + * If any error occurs, the object cursor will be invalidated. + */ +int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) { + static size_t no_extra = 0; + + return asn1_enter_partial ( cursor, type, &no_extra ); +} + +/** * Skip ASN.1 object if present * * @v cursor ASN.1 object cursor @@ -181,26 +216,26 @@ int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) { * @ret rc Return status code * * The object cursor will be updated to point to the next ASN.1 - * object. If any error occurs, the object cursor will not be - * modified. + * object. + * + * If the expected type is not found, the object cursor will not be + * modified. If any other error occurs, the object cursor will be + * invalidated. */ int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) { int len; + /* Parse current object */ len = asn1_start ( cursor, type, 0 ); if ( len < 0 ) return len; + /* Update cursor */ cursor->data += len; cursor->len -= len; + DBGC ( cursor, "ASN1 %p skipped object type %02x (len %x)\n", cursor, type, len ); - - if ( ! cursor->len ) { - DBGC ( cursor, "ASN1 %p reached end of object\n", cursor ); - return -ENOENT; - } - return 0; } @@ -212,8 +247,9 @@ int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) { * @ret rc Return status code * * The object cursor will be updated to point to the next ASN.1 - * object. If any error occurs, the object cursor will be - * invalidated. + * object. + * + * If any error occurs, the object cursor will be invalidated. */ int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) { int rc; @@ -234,8 +270,9 @@ int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) { * @ret rc Return status code * * The object cursor will be shrunk to contain only the current ASN.1 - * object. If any error occurs, the object cursor will be - * invalidated. + * object. + * + * If any error occurs, the object cursor will be invalidated. */ int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type ) { struct asn1_cursor temp; @@ -473,18 +510,26 @@ asn1_find_algorithm ( const struct asn1_cursor *cursor ) { * * @v cursor ASN.1 object cursor * @ret algorithm Algorithm + * @ret params Algorithm parameters, or NULL * @ret rc Return status code */ int asn1_algorithm ( const struct asn1_cursor *cursor, - struct asn1_algorithm **algorithm ) { + struct asn1_algorithm **algorithm, + struct asn1_cursor *params ) { struct asn1_cursor contents; int rc; - /* Enter signatureAlgorithm */ + /* Enter algorithm */ memcpy ( &contents, cursor, sizeof ( contents ) ); asn1_enter ( &contents, ASN1_SEQUENCE ); - /* Enter algorithm */ + /* Get raw parameters, if applicable */ + if ( params ) { + memcpy ( params, &contents, sizeof ( *params ) ); + asn1_skip_any ( params ); + } + + /* Enter algorithm identifier */ if ( ( rc = asn1_enter ( &contents, ASN1_OID ) ) != 0 ) { DBGC ( cursor, "ASN1 %p cannot locate algorithm OID:\n", cursor ); @@ -500,6 +545,14 @@ int asn1_algorithm ( const struct asn1_cursor *cursor, return -ENOTSUP_ALGORITHM; } + /* Parse parameters, if applicable */ + if ( params && (*algorithm)->parse && + ( ( rc = (*algorithm)->parse ( *algorithm, params ) ) != 0 ) ) { + DBGC ( cursor, "ASN1 %p cannot parse %s parameters: %s\n", + cursor, (*algorithm)->name, strerror ( rc ) ); + return rc; + } + return 0; } @@ -515,7 +568,7 @@ int asn1_pubkey_algorithm ( const struct asn1_cursor *cursor, int rc; /* Parse algorithm */ - if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 ) + if ( ( rc = asn1_algorithm ( cursor, algorithm, NULL ) ) != 0 ) return rc; /* Check algorithm has a public key */ @@ -541,7 +594,7 @@ int asn1_digest_algorithm ( const struct asn1_cursor *cursor, int rc; /* Parse algorithm */ - if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 ) + if ( ( rc = asn1_algorithm ( cursor, algorithm, NULL ) ) != 0 ) return rc; /* Check algorithm has a digest */ @@ -556,6 +609,34 @@ int asn1_digest_algorithm ( const struct asn1_cursor *cursor, } /** + * Parse ASN.1 OID-identified cipher algorithm + * + * @v cursor ASN.1 object cursor + * @ret algorithm Algorithm + * @ret params Algorithm parameters, or NULL + * @ret rc Return status code + */ +int asn1_cipher_algorithm ( const struct asn1_cursor *cursor, + struct asn1_algorithm **algorithm, + struct asn1_cursor *params ) { + int rc; + + /* Parse algorithm */ + if ( ( rc = asn1_algorithm ( cursor, algorithm, params ) ) != 0 ) + return rc; + + /* Check algorithm has a cipher */ + if ( ! (*algorithm)->cipher ) { + DBGC ( cursor, "ASN1 %p algorithm %s is not a cipher " + "algorithm:\n", cursor, (*algorithm)->name ); + DBGC_HDA ( cursor, 0, cursor->data, cursor->len ); + return -ENOTTY_ALGORITHM; + } + + return 0; +} + +/** * Parse ASN.1 OID-identified signature algorithm * * @v cursor ASN.1 object cursor @@ -567,7 +648,7 @@ int asn1_signature_algorithm ( const struct asn1_cursor *cursor, int rc; /* Parse algorithm */ - if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 ) + if ( ( rc = asn1_algorithm ( cursor, algorithm, NULL ) ) != 0 ) return rc; /* Check algorithm has a public key */ @@ -602,7 +683,7 @@ int asn1_check_algorithm ( const struct asn1_cursor *cursor, int rc; /* Parse algorithm */ - if ( ( rc = asn1_algorithm ( cursor, &actual ) ) != 0 ) + if ( ( rc = asn1_algorithm ( cursor, &actual, NULL ) ) != 0 ) return rc; /* Check algorithm matches */ @@ -616,6 +697,47 @@ int asn1_check_algorithm ( const struct asn1_cursor *cursor, } /** + * Parse ASN.1 CBC cipher parameters + * + * @v algorithm Algorithm + * @v param Parameters to parse + * @ret rc Return status code + */ +int asn1_parse_cbc ( struct asn1_algorithm *algorithm, + struct asn1_cursor *params ) { + struct cipher_algorithm *cipher = algorithm->cipher; + + /* Sanity check */ + assert ( cipher != NULL ); + + /* Enter parameters */ + asn1_enter ( params, ASN1_OCTET_STRING ); + + /* Check length */ + if ( params->len != cipher->blocksize ) + return -EINVAL; + + return 0; +} + +/** + * Parse ASN.1 GCM cipher parameters + * + * @v algorithm Algorithm + * @v param Parameters to parse + * @ret rc Return status code + */ +int asn1_parse_gcm ( struct asn1_algorithm *algorithm __unused, + struct asn1_cursor *params ) { + + /* Enter parameters */ + asn1_enter ( params, ASN1_SEQUENCE ); + + /* Enter nonce */ + return asn1_enter ( params, ASN1_OCTET_STRING ); +} + +/** * Parse ASN.1 GeneralizedTime * * @v cursor ASN.1 cursor diff --git a/src/crypto/certstore.c b/src/crypto/certstore.c index 2676c7e..31797c4 100644 --- a/src/crypto/certstore.c +++ b/src/crypto/certstore.c @@ -69,66 +69,28 @@ static struct asn1_cursor certstore_raw[] = { static struct x509_certificate certstore_certs[ sizeof ( certstore_raw ) / sizeof ( certstore_raw[0] ) ]; -/** Certificate store */ -struct x509_chain certstore = { - .refcnt = REF_INIT ( ref_no_free ), - .links = LIST_HEAD_INIT ( certstore.links ), -}; - /** * Mark stored certificate as most recently used * + * @v store Certificate store * @v cert X.509 certificate - * @ret cert X.509 certificate */ -static struct x509_certificate * -certstore_found ( struct x509_certificate *cert ) { +static void certstore_found ( struct x509_chain *store, + struct x509_certificate *cert ) { /* Mark as most recently used */ list_del ( &cert->store.list ); - list_add ( &cert->store.list, &certstore.links ); - DBGC2 ( &certstore, "CERTSTORE found certificate %s\n", + list_add ( &cert->store.list, &store->links ); + DBGC2 ( store, "CERTSTORE found certificate %s\n", x509_name ( cert ) ); - - return cert; -} - -/** - * Find certificate in store - * - * @v raw Raw certificate data - * @ret cert X.509 certificate, or NULL if not found - */ -struct x509_certificate * certstore_find ( struct asn1_cursor *raw ) { - struct x509_certificate *cert; - - /* Search for certificate within store */ - list_for_each_entry ( cert, &certstore.links, store.list ) { - if ( asn1_compare ( raw, &cert->raw ) == 0 ) - return certstore_found ( cert ); - } - return NULL; } -/** - * Find certificate in store corresponding to a private key - * - * @v key Private key - * @ret cert X.509 certificate, or NULL if not found - */ -struct x509_certificate * certstore_find_key ( struct private_key *key ) { - struct x509_certificate *cert; - - /* Search for certificate within store */ - list_for_each_entry ( cert, &certstore.links, store.list ) { - if ( pubkey_match ( cert->signature_algorithm->pubkey, - key->builder.data, key->builder.len, - cert->subject.public_key.raw.data, - cert->subject.public_key.raw.len ) == 0 ) - return certstore_found ( cert ); - } - return NULL; -} +/** Certificate store */ +struct x509_chain certstore = { + .refcnt = REF_INIT ( ref_no_free ), + .links = LIST_HEAD_INIT ( certstore.links ), + .found = certstore_found, +}; /** * Add certificate to store @@ -219,7 +181,7 @@ static void certstore_init ( void ) { /* Skip if certificate already present in store */ raw = &certstore_raw[i]; - if ( ( cert = certstore_find ( raw ) ) != NULL ) { + if ( ( cert = x509_find ( &certstore, raw ) ) != NULL ) { DBGC ( &certstore, "CERTSTORE permanent certificate %d " "is a duplicate of %s\n", i, x509_name ( cert )); continue; diff --git a/src/crypto/cms.c b/src/crypto/cms.c index 9511cec..6c8217c 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -37,8 +37,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <errno.h> #include <ipxe/asn1.h> #include <ipxe/x509.h> +#include <ipxe/image.h> #include <ipxe/malloc.h> #include <ipxe/uaccess.h> +#include <ipxe/privkey.h> #include <ipxe/cms.h> /* Disambiguate the various error causes */ @@ -58,60 +60,109 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); __einfo_error ( EINFO_EACCES_NO_SIGNATURES ) #define EINFO_EACCES_NO_SIGNATURES \ __einfo_uniqify ( EINFO_EACCES, 0x05, "No signatures present" ) -#define EINVAL_DIGEST \ - __einfo_error ( EINFO_EINVAL_DIGEST ) -#define EINFO_EINVAL_DIGEST \ - __einfo_uniqify ( EINFO_EINVAL, 0x01, "Not a digest algorithm" ) -#define EINVAL_PUBKEY \ - __einfo_error ( EINFO_EINVAL_PUBKEY ) -#define EINFO_EINVAL_PUBKEY \ - __einfo_uniqify ( EINFO_EINVAL, 0x02, "Not a public-key algorithm" ) -#define ENOTSUP_SIGNEDDATA \ - __einfo_error ( EINFO_ENOTSUP_SIGNEDDATA ) -#define EINFO_ENOTSUP_SIGNEDDATA \ - __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Not a digital signature" ) - -/** "pkcs7-signedData" object identifier */ +#define EACCES_NO_RECIPIENTS \ + __einfo_error ( EINFO_EACCES_NO_RECIPIENTS ) +#define EINFO_EACCES_NO_RECIPIENTS \ + __einfo_uniqify ( EINFO_EACCES, 0x06, "No usable recipients" ) +#define EACCES_LEN \ + __einfo_error ( EINFO_EACCES_LEN ) +#define EINFO_EACCES_LEN \ + __einfo_uniqify ( EINFO_EACCES, 0x07, "Bad file length" ) +#define EACCES_PAD \ + __einfo_error ( EINFO_EACCES_PAD ) +#define EINFO_EACCES_PAD \ + __einfo_uniqify ( EINFO_EACCES, 0x08, "Bad block padding" ) +#define EACCES_MAC \ + __einfo_error ( EINFO_EACCES_MAC ) +#define EINFO_EACCES_MAC \ + __einfo_uniqify ( EINFO_EACCES, 0x09, "Invalid MAC" ) +#define ENOTSUP_TYPE \ + __einfo_error ( EINFO_ENOTSUP_TYPE ) +#define EINFO_ENOTSUP_TYPE \ + __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unrecognised message type" ) + +/** Buffer size for decryption + * + * Must be at least 256 to allow block padding to be removed if + * needed. + */ +#define CMS_DECRYPT_BLKSZ 2048 + +static int cms_parse_signed ( struct cms_message *cms, + const struct asn1_cursor *raw ); +static int cms_parse_enveloped ( struct cms_message *cms, + const struct asn1_cursor *raw ); + +/** "id-signedData" object identifier */ static uint8_t oid_signeddata[] = { ASN1_OID_SIGNEDDATA }; -/** "pkcs7-signedData" object identifier cursor */ -static struct asn1_cursor oid_signeddata_cursor = - ASN1_CURSOR ( oid_signeddata ); +/** "id-envelopedData" object identifier */ +static uint8_t oid_envelopeddata[] = { ASN1_OID_ENVELOPEDDATA }; + +/** "id-authEnvelopedData" object identifier */ +static uint8_t oid_authenvelopeddata[] = { ASN1_OID_AUTHENVELOPEDDATA }; + +/** CMS message types */ +static struct cms_type cms_types[] = { + { + .name = "signed", + .oid = ASN1_CURSOR ( oid_signeddata ), + .parse = cms_parse_signed, + }, + { + .name = "enveloped", + .oid = ASN1_CURSOR ( oid_envelopeddata ), + .parse = cms_parse_enveloped, + }, + { + .name = "authEnveloped", + .oid = ASN1_CURSOR ( oid_authenvelopeddata ), + .parse = cms_parse_enveloped, + } +}; /** - * Parse CMS signature content type + * Parse CMS message content type * - * @v sig CMS signature + * @v cms CMS message * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse_content_type ( struct cms_signature *sig, +static int cms_parse_content_type ( struct cms_message *cms, const struct asn1_cursor *raw ) { struct asn1_cursor cursor; + struct cms_type *type; + unsigned int i; /* Enter contentType */ memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_enter ( &cursor, ASN1_OID ); - /* Check OID is pkcs7-signedData */ - if ( asn1_compare ( &cursor, &oid_signeddata_cursor ) != 0 ) { - DBGC ( sig, "CMS %p does not contain signedData:\n", sig ); - DBGC_HDA ( sig, 0, raw->data, raw->len ); - return -ENOTSUP_SIGNEDDATA; + /* Check for a recognised OID */ + for ( i = 0 ; i < ( sizeof ( cms_types ) / + sizeof ( cms_types[0] ) ) ; i++ ) { + type = &cms_types[i]; + if ( asn1_compare ( &cursor, &type->oid ) == 0 ) { + cms->type = type; + DBGC ( cms, "CMS %p contains %sData\n", + cms, type->name ); + return 0; + } } - DBGC ( sig, "CMS %p contains signedData\n", sig ); - return 0; + DBGC ( cms, "CMS %p is not a recognised message type:\n", cms ); + DBGC_HDA ( cms, 0, raw->data, raw->len ); + return -ENOTSUP_TYPE; } /** - * Parse CMS signature certificate list + * Parse CMS message certificate list * - * @v sig CMS signature + * @v cms CMS message * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse_certificates ( struct cms_signature *sig, +static int cms_parse_certificates ( struct cms_message *cms, const struct asn1_cursor *raw ) { struct asn1_cursor cursor; struct x509_certificate *cert; @@ -125,16 +176,16 @@ static int cms_parse_certificates ( struct cms_signature *sig, while ( cursor.len ) { /* Add certificate to chain */ - if ( ( rc = x509_append_raw ( sig->certificates, cursor.data, + if ( ( rc = x509_append_raw ( cms->certificates, cursor.data, cursor.len ) ) != 0 ) { - DBGC ( sig, "CMS %p could not append certificate: %s\n", - sig, strerror ( rc) ); - DBGC_HDA ( sig, 0, cursor.data, cursor.len ); + DBGC ( cms, "CMS %p could not append certificate: %s\n", + cms, strerror ( rc) ); + DBGC_HDA ( cms, 0, cursor.data, cursor.len ); return rc; } - cert = x509_last ( sig->certificates ); - DBGC ( sig, "CMS %p found certificate %s\n", - sig, x509_name ( cert ) ); + cert = x509_last ( cms->certificates ); + DBGC ( cms, "CMS %p found certificate %s\n", + cms, x509_name ( cert ) ); /* Move to next certificate */ asn1_skip_any ( &cursor ); @@ -144,44 +195,16 @@ static int cms_parse_certificates ( struct cms_signature *sig, } /** - * Identify CMS signature certificate by issuer and serial number - * - * @v sig CMS signature - * @v issuer Issuer - * @v serial Serial number - * @ret cert X.509 certificate, or NULL if not found - */ -static struct x509_certificate * -cms_find_issuer_serial ( struct cms_signature *sig, - const struct asn1_cursor *issuer, - const struct asn1_cursor *serial ) { - struct x509_link *link; - struct x509_certificate *cert; - - /* Scan through certificate list */ - list_for_each_entry ( link, &sig->certificates->links, list ) { - - /* Check issuer and serial number */ - cert = link->cert; - if ( ( asn1_compare ( issuer, &cert->issuer.raw ) == 0 ) && - ( asn1_compare ( serial, &cert->serial.raw ) == 0 ) ) - return cert; - } - - return NULL; -} - -/** - * Parse CMS signature signer identifier + * Parse CMS message participant identifier * - * @v sig CMS signature - * @v info Signer information to fill in + * @v cms CMS message + * @v part Participant information to fill in * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse_signer_identifier ( struct cms_signature *sig, - struct cms_signer_info *info, - const struct asn1_cursor *raw ) { +static int cms_parse_identifier ( struct cms_message *cms, + struct cms_participant *part, + const struct asn1_cursor *raw ) { struct asn1_cursor cursor; struct asn1_cursor serial; struct asn1_cursor issuer; @@ -195,46 +218,46 @@ static int cms_parse_signer_identifier ( struct cms_signature *sig, /* Identify issuer */ memcpy ( &issuer, &cursor, sizeof ( issuer ) ); if ( ( rc = asn1_shrink ( &issuer, ASN1_SEQUENCE ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not locate issuer: %s\n", - sig, info, strerror ( rc ) ); - DBGC_HDA ( sig, 0, raw->data, raw->len ); + DBGC ( cms, "CMS %p/%p could not locate issuer: %s\n", + cms, part, strerror ( rc ) ); + DBGC_HDA ( cms, 0, raw->data, raw->len ); return rc; } - DBGC ( sig, "CMS %p/%p issuer is:\n", sig, info ); - DBGC_HDA ( sig, 0, issuer.data, issuer.len ); + DBGC ( cms, "CMS %p/%p issuer is:\n", cms, part ); + DBGC_HDA ( cms, 0, issuer.data, issuer.len ); asn1_skip_any ( &cursor ); /* Identify serialNumber */ memcpy ( &serial, &cursor, sizeof ( serial ) ); if ( ( rc = asn1_shrink ( &serial, ASN1_INTEGER ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not locate serialNumber: %s\n", - sig, info, strerror ( rc ) ); - DBGC_HDA ( sig, 0, raw->data, raw->len ); + DBGC ( cms, "CMS %p/%p could not locate serialNumber: %s\n", + cms, part, strerror ( rc ) ); + DBGC_HDA ( cms, 0, raw->data, raw->len ); return rc; } - DBGC ( sig, "CMS %p/%p serial number is:\n", sig, info ); - DBGC_HDA ( sig, 0, serial.data, serial.len ); + DBGC ( cms, "CMS %p/%p serial number is:\n", cms, part ); + DBGC_HDA ( cms, 0, serial.data, serial.len ); /* Identify certificate */ - cert = cms_find_issuer_serial ( sig, &issuer, &serial ); + cert = x509_find_issuer_serial ( cms->certificates, &issuer, &serial ); if ( ! cert ) { - DBGC ( sig, "CMS %p/%p could not identify signer's " - "certificate\n", sig, info ); - return -ENOENT; + DBGC ( cms, "CMS %p/%p could not identify certificate\n", + cms, part ); + return ( cms_is_signature ( cms ) ? -ENOENT : 0 ); } /* Append certificate to chain */ - if ( ( rc = x509_append ( info->chain, cert ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not append certificate: %s\n", - sig, info, strerror ( rc ) ); + if ( ( rc = x509_append ( part->chain, cert ) ) != 0 ) { + DBGC ( cms, "CMS %p/%p could not append certificate: %s\n", + cms, part, strerror ( rc ) ); return rc; } /* Append remaining certificates to chain */ - if ( ( rc = x509_auto_append ( info->chain, - sig->certificates ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not append certificates: %s\n", - sig, info, strerror ( rc ) ); + if ( ( rc = x509_auto_append ( part->chain, + cms->certificates ) ) != 0 ) { + DBGC ( cms, "CMS %p/%p could not append certificates: %s\n", + cms, part, strerror ( rc ) ); return rc; } @@ -242,173 +265,285 @@ static int cms_parse_signer_identifier ( struct cms_signature *sig, } /** - * Parse CMS signature digest algorithm + * Parse CMS message digest algorithm * - * @v sig CMS signature - * @v info Signer information to fill in + * @v cms CMS message + * @v part Participant information to fill in * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse_digest_algorithm ( struct cms_signature *sig, - struct cms_signer_info *info, +static int cms_parse_digest_algorithm ( struct cms_message *cms, + struct cms_participant *part, const struct asn1_cursor *raw ) { struct asn1_algorithm *algorithm; int rc; /* Identify algorithm */ if ( ( rc = asn1_digest_algorithm ( raw, &algorithm ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not identify digest algorithm: " - "%s\n", sig, info, strerror ( rc ) ); - DBGC_HDA ( sig, 0, raw->data, raw->len ); + DBGC ( cms, "CMS %p/%p could not identify digest algorithm: " + "%s\n", cms, part, strerror ( rc ) ); + DBGC_HDA ( cms, 0, raw->data, raw->len ); return rc; } /* Record digest algorithm */ - info->digest = algorithm->digest; - DBGC ( sig, "CMS %p/%p digest algorithm is %s\n", - sig, info, algorithm->name ); + part->digest = algorithm->digest; + DBGC ( cms, "CMS %p/%p digest algorithm is %s\n", + cms, part, algorithm->name ); return 0; } /** - * Parse CMS signature algorithm + * Parse CMS message public-key algorithm * - * @v sig CMS signature - * @v info Signer information to fill in + * @v cms CMS message + * @v part Participant information to fill in * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse_signature_algorithm ( struct cms_signature *sig, - struct cms_signer_info *info, - const struct asn1_cursor *raw ) { +static int cms_parse_pubkey_algorithm ( struct cms_message *cms, + struct cms_participant *part, + const struct asn1_cursor *raw ) { struct asn1_algorithm *algorithm; int rc; /* Identify algorithm */ if ( ( rc = asn1_pubkey_algorithm ( raw, &algorithm ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not identify public-key " - "algorithm: %s\n", sig, info, strerror ( rc ) ); - DBGC_HDA ( sig, 0, raw->data, raw->len ); + DBGC ( cms, "CMS %p/%p could not identify public-key " + "algorithm: %s\n", cms, part, strerror ( rc ) ); + DBGC_HDA ( cms, 0, raw->data, raw->len ); return rc; } - /* Record signature algorithm */ - info->pubkey = algorithm->pubkey; - DBGC ( sig, "CMS %p/%p public-key algorithm is %s\n", - sig, info, algorithm->name ); + /* Record public-key algorithm */ + part->pubkey = algorithm->pubkey; + DBGC ( cms, "CMS %p/%p public-key algorithm is %s\n", + cms, part, algorithm->name ); return 0; } /** - * Parse CMS signature value + * Parse CMS message cipher algorithm * - * @v sig CMS signature - * @v info Signer information to fill in + * @v cms CMS message * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse_signature_value ( struct cms_signature *sig, - struct cms_signer_info *info, - const struct asn1_cursor *raw ) { - struct asn1_cursor cursor; +static int cms_parse_cipher_algorithm ( struct cms_message *cms, + const struct asn1_cursor *raw ) { + struct asn1_algorithm *algorithm; int rc; - /* Enter signature */ - memcpy ( &cursor, raw, sizeof ( cursor ) ); - if ( ( rc = asn1_enter ( &cursor, ASN1_OCTET_STRING ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not locate signature:\n", - sig, info ); - DBGC_HDA ( sig, 0, raw->data, raw->len ); + /* Identify algorithm */ + if ( ( rc = asn1_cipher_algorithm ( raw, &algorithm, + &cms->iv ) ) != 0 ) { + DBGC ( cms, "CMS %p could not identify cipher algorithm: %s\n", + cms, strerror ( rc ) ); + DBGC_HDA ( cms, 0, raw->data, raw->len ); return rc; } - /* Record signature */ - info->signature_len = cursor.len; - info->signature = malloc ( info->signature_len ); - if ( ! info->signature ) - return -ENOMEM; - memcpy ( info->signature, cursor.data, info->signature_len ); - DBGC ( sig, "CMS %p/%p signature value is:\n", sig, info ); - DBGC_HDA ( sig, 0, info->signature, info->signature_len ); + /* Record cipher */ + cms->cipher = algorithm->cipher; + DBGC ( cms, "CMS %p cipher algorithm is %s\n", cms, algorithm->name ); return 0; } /** - * Parse CMS signature signer information + * Parse CMS message signature or key value * - * @v sig CMS signature - * @v info Signer information to fill in + * @v cms CMS message + * @v part Participant information to fill in * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse_signer_info ( struct cms_signature *sig, - struct cms_signer_info *info, +static int cms_parse_value ( struct cms_message *cms, + struct cms_participant *part, + const struct asn1_cursor *raw ) { + int rc; + + /* Enter signature or encryptedKey */ + memcpy ( &part->value, raw, sizeof ( part->value ) ); + if ( ( rc = asn1_enter ( &part->value, ASN1_OCTET_STRING ) ) != 0 ) { + DBGC ( cms, "CMS %p/%p could not locate value:\n", + cms, part ); + DBGC_HDA ( cms, 0, raw->data, raw->len ); + return rc; + } + DBGC ( cms, "CMS %p/%p value is:\n", cms, part ); + DBGC_HDA ( cms, 0, part->value.data, part->value.len ); + + return 0; +} + +/** + * Parse CMS message participant information + * + * @v cms CMS message + * @v part Participant information to fill in + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int cms_parse_participant ( struct cms_message *cms, + struct cms_participant *part, const struct asn1_cursor *raw ) { struct asn1_cursor cursor; int rc; - /* Enter signerInfo */ + /* Enter signerInfo or ktri */ memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_enter ( &cursor, ASN1_SEQUENCE ); /* Skip version */ asn1_skip ( &cursor, ASN1_INTEGER ); - /* Parse sid */ - if ( ( rc = cms_parse_signer_identifier ( sig, info, &cursor ) ) != 0 ) + /* Parse sid or rid */ + if ( ( rc = cms_parse_identifier ( cms, part, &cursor ) ) != 0 ) return rc; asn1_skip_any ( &cursor ); - /* Parse digestAlgorithm */ - if ( ( rc = cms_parse_digest_algorithm ( sig, info, &cursor ) ) != 0 ) - return rc; - asn1_skip_any ( &cursor ); + /* Parse signature-only objects */ + if ( cms_is_signature ( cms ) ) { - /* Skip signedAttrs, if present */ - asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) ); + /* Parse digestAlgorithm */ + if ( ( rc = cms_parse_digest_algorithm ( cms, part, + &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + + /* Skip signedAttrs, if present */ + asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) ); + } - /* Parse signatureAlgorithm */ - if ( ( rc = cms_parse_signature_algorithm ( sig, info, &cursor ) ) != 0) + /* Parse signatureAlgorithm or contentEncryptionAlgorithm */ + if ( ( rc = cms_parse_pubkey_algorithm ( cms, part, &cursor ) ) != 0 ) return rc; asn1_skip_any ( &cursor ); - /* Parse signature */ - if ( ( rc = cms_parse_signature_value ( sig, info, &cursor ) ) != 0 ) + /* Parse signature or encryptedKey */ + if ( ( rc = cms_parse_value ( cms, part, &cursor ) ) != 0 ) return rc; return 0; } /** - * Parse CMS signature from ASN.1 data + * Parse CMS message participants information * - * @v sig CMS signature + * @v cms CMS message * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse ( struct cms_signature *sig, - const struct asn1_cursor *raw ) { +static int cms_parse_participants ( struct cms_message *cms, + const struct asn1_cursor *raw ) { struct asn1_cursor cursor; - struct cms_signer_info *info; + struct cms_participant *part; int rc; - /* Enter contentInfo */ + /* Enter signerInfos or recipientInfos */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SET ); + + /* Add each signerInfo or recipientInfo. Errors are handled + * by ensuring that cms_put() will always be able to free any + * allocated memory. + */ + while ( cursor.len ) { + + /* Allocate participant information block */ + part = zalloc ( sizeof ( *part ) ); + if ( ! part ) + return -ENOMEM; + list_add ( &part->list, &cms->participants ); + + /* Allocate certificate chain */ + part->chain = x509_alloc_chain(); + if ( ! part->chain ) + return -ENOMEM; + + /* Parse signerInfo or recipientInfo */ + if ( ( rc = cms_parse_participant ( cms, part, + &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + } + + return 0; +} + +/** + * Parse CMS message encrypted content information + * + * @v cms CMS message + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int cms_parse_encrypted ( struct cms_message *cms, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + int rc; + + /* Enter encryptedContentInfo */ memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_enter ( &cursor, ASN1_SEQUENCE ); - /* Parse contentType */ + /* Skip contentType */ + asn1_skip ( &cursor, ASN1_OID ); - if ( ( rc = cms_parse_content_type ( sig, &cursor ) ) != 0 ) + /* Parse contentEncryptionAlgorithm */ + if ( ( rc = cms_parse_cipher_algorithm ( cms, &cursor ) ) != 0 ) return rc; - asn1_skip_any ( &cursor ); - /* Enter content */ - asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) ); + return 0; +} + +/** + * Parse CMS message MAC + * + * @v cms CMS message + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int cms_parse_mac ( struct cms_message *cms, + const struct asn1_cursor *raw ) { + int rc; + + /* Enter mac */ + memcpy ( &cms->mac, raw, sizeof ( cms->mac ) ); + if ( ( rc = asn1_enter ( &cms->mac, ASN1_OCTET_STRING ) ) != 0 ) { + DBGC ( cms, "CMS %p could not locate mac: %s\n", + cms, strerror ( rc ) ); + DBGC_HDA ( cms, 0, raw->data, raw->len ); + return rc; + } + DBGC ( cms, "CMS %p mac is:\n", cms ); + DBGC_HDA ( cms, 0, cms->mac.data, cms->mac.len ); + + return 0; +} + +/** + * Parse CMS signed data + * + * @v cms CMS message + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int cms_parse_signed ( struct cms_message *cms, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + int rc; + + /* Allocate certificate list */ + cms->certificates = x509_alloc_chain(); + if ( ! cms->certificates ) + return -ENOMEM; /* Enter signedData */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_enter ( &cursor, ASN1_SEQUENCE ); /* Skip version */ @@ -421,108 +556,159 @@ static int cms_parse ( struct cms_signature *sig, asn1_skip ( &cursor, ASN1_SEQUENCE ); /* Parse certificates */ - if ( ( rc = cms_parse_certificates ( sig, &cursor ) ) != 0 ) + if ( ( rc = cms_parse_certificates ( cms, &cursor ) ) != 0 ) return rc; asn1_skip_any ( &cursor ); /* Skip crls, if present */ asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 1 ) ); - /* Enter signerInfos */ - asn1_enter ( &cursor, ASN1_SET ); + /* Parse signerInfos */ + if ( ( rc = cms_parse_participants ( cms, &cursor ) ) != 0 ) + return rc; - /* Add each signerInfo. Errors are handled by ensuring that - * cms_put() will always be able to free any allocated memory. - */ - while ( cursor.len ) { + return 0; +} - /* Allocate signer information block */ - info = zalloc ( sizeof ( *info ) ); - if ( ! info ) - return -ENOMEM; - list_add ( &info->list, &sig->info ); +/** + * Parse CMS enveloped data + * + * @v cms CMS message + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int cms_parse_enveloped ( struct cms_message *cms, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + int rc; - /* Allocate certificate chain */ - info->chain = x509_alloc_chain(); - if ( ! info->chain ) - return -ENOMEM; + /* Enter envelopedData or authEnvelopedData */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); - /* Parse signerInfo */ - if ( ( rc = cms_parse_signer_info ( sig, info, - &cursor ) ) != 0 ) - return rc; - asn1_skip_any ( &cursor ); - } + /* Skip version */ + asn1_skip ( &cursor, ASN1_INTEGER ); + + /* Skip originatorInfo, if present */ + asn1_skip_if_exists ( &cursor, ASN1_IMPLICIT_TAG ( 0 ) ); + + /* Parse recipientInfos */ + if ( ( rc = cms_parse_participants ( cms, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + + /* Parse encryptedContentInfo or authEncryptedContentInfo */ + if ( ( rc = cms_parse_encrypted ( cms, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + assert ( cms->cipher != NULL ); + + /* Skip unprotectedAttrs or authAttrs, if present */ + asn1_skip_if_exists ( &cursor, ASN1_IMPLICIT_TAG ( 1 ) ); + + /* Parse mac, if present */ + if ( ( cms->cipher->authsize != 0 ) && + ( ( rc = cms_parse_mac ( cms, &cursor ) ) != 0 ) ) + return rc; return 0; } /** - * Free CMS signature + * Parse CMS message from ASN.1 data + * + * @v cms CMS message + * @ret rc Return status code + */ +static int cms_parse ( struct cms_message *cms ) { + struct asn1_cursor cursor; + int rc; + + /* Enter contentInfo */ + memcpy ( &cursor, cms->raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Parse contentType */ + if ( ( rc = cms_parse_content_type ( cms, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + + /* Enter content */ + asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) ); + + /* Parse type-specific content */ + if ( ( rc = cms->type->parse ( cms, &cursor ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Free CMS message * * @v refcnt Reference count */ static void cms_free ( struct refcnt *refcnt ) { - struct cms_signature *sig = - container_of ( refcnt, struct cms_signature, refcnt ); - struct cms_signer_info *info; - struct cms_signer_info *tmp; - - list_for_each_entry_safe ( info, tmp, &sig->info, list ) { - list_del ( &info->list ); - x509_chain_put ( info->chain ); - free ( info->signature ); - free ( info ); - } - x509_chain_put ( sig->certificates ); - free ( sig ); + struct cms_message *cms = + container_of ( refcnt, struct cms_message, refcnt ); + struct cms_participant *part; + struct cms_participant *tmp; + + list_for_each_entry_safe ( part, tmp, &cms->participants, list ) { + list_del ( &part->list ); + x509_chain_put ( part->chain ); + free ( part ); + } + x509_chain_put ( cms->certificates ); + free ( cms->raw ); + free ( cms ); } /** - * Create CMS signature + * Create CMS message * - * @v data Raw signature data - * @v len Length of raw data - * @ret sig CMS signature + * @v image Image + * @ret sig CMS message * @ret rc Return status code * - * On success, the caller holds a reference to the CMS signature, and + * On success, the caller holds a reference to the CMS message, and * is responsible for ultimately calling cms_put(). */ -int cms_signature ( const void *data, size_t len, struct cms_signature **sig ) { - struct asn1_cursor cursor; +int cms_message ( struct image *image, struct cms_message **cms ) { + int next; int rc; - /* Allocate and initialise signature */ - *sig = zalloc ( sizeof ( **sig ) ); - if ( ! *sig ) { + /* Allocate and initialise message */ + *cms = zalloc ( sizeof ( **cms ) ); + if ( ! *cms ) { rc = -ENOMEM; goto err_alloc; } - ref_init ( &(*sig)->refcnt, cms_free ); - INIT_LIST_HEAD ( &(*sig)->info ); - - /* Allocate certificate list */ - (*sig)->certificates = x509_alloc_chain(); - if ( ! (*sig)->certificates ) { - rc = -ENOMEM; - goto err_alloc_chain; + ref_init ( &(*cms)->refcnt, cms_free ); + INIT_LIST_HEAD ( &(*cms)->participants ); + (*cms)->cipher = &cipher_null; + + /* Get raw message data */ + next = image_asn1 ( image, 0, &(*cms)->raw ); + if ( next < 0 ) { + rc = next; + DBGC ( *cms, "CMS %p could not get raw ASN.1 data: %s\n", + *cms, strerror ( rc ) ); + goto err_asn1; } - /* Initialise cursor */ - cursor.data = data; - cursor.len = len; - asn1_shrink_any ( &cursor ); + /* Use only first message in image */ + asn1_shrink_any ( (*cms)->raw ); - /* Parse signature */ - if ( ( rc = cms_parse ( *sig, &cursor ) ) != 0 ) + /* Parse message */ + if ( ( rc = cms_parse ( *cms ) ) != 0 ) goto err_parse; return 0; err_parse: - err_alloc_chain: - cms_put ( *sig ); + err_asn1: + cms_put ( *cms ); err_alloc: return rc; } @@ -530,16 +716,16 @@ int cms_signature ( const void *data, size_t len, struct cms_signature **sig ) { /** * Calculate digest of CMS-signed data * - * @v sig CMS signature - * @v info Signer information + * @v cms CMS message + * @v part Participant information * @v data Signed data * @v len Length of signed data * @v out Digest output */ -static void cms_digest ( struct cms_signature *sig, - struct cms_signer_info *info, +static void cms_digest ( struct cms_message *cms, + struct cms_participant *part, userptr_t data, size_t len, void *out ) { - struct digest_algorithm *digest = info->digest; + struct digest_algorithm *digest = part->digest; uint8_t ctx[ digest->ctxsize ]; uint8_t block[ digest->blocksize ]; size_t offset = 0; @@ -562,62 +748,50 @@ static void cms_digest ( struct cms_signature *sig, /* Finalise digest */ digest_final ( digest, ctx, out ); - DBGC ( sig, "CMS %p/%p digest value:\n", sig, info ); - DBGC_HDA ( sig, 0, out, digest->digestsize ); + DBGC ( cms, "CMS %p/%p digest value:\n", cms, part ); + DBGC_HDA ( cms, 0, out, digest->digestsize ); } /** * Verify digest of CMS-signed data * - * @v sig CMS signature - * @v info Signer information + * @v cms CMS message + * @v part Participant information * @v cert Corresponding certificate * @v data Signed data * @v len Length of signed data * @ret rc Return status code */ -static int cms_verify_digest ( struct cms_signature *sig, - struct cms_signer_info *info, +static int cms_verify_digest ( struct cms_message *cms, + struct cms_participant *part, struct x509_certificate *cert, userptr_t data, size_t len ) { - struct digest_algorithm *digest = info->digest; - struct pubkey_algorithm *pubkey = info->pubkey; - struct x509_public_key *public_key = &cert->subject.public_key; + struct digest_algorithm *digest = part->digest; + struct pubkey_algorithm *pubkey = part->pubkey; + const struct asn1_cursor *key = &cert->subject.public_key.raw; + const struct asn1_cursor *value = &part->value; uint8_t digest_out[ digest->digestsize ]; - uint8_t ctx[ pubkey->ctxsize ]; int rc; /* Generate digest */ - cms_digest ( sig, info, data, len, digest_out ); - - /* Initialise public-key algorithm */ - if ( ( rc = pubkey_init ( pubkey, ctx, public_key->raw.data, - public_key->raw.len ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not initialise public key: %s\n", - sig, info, strerror ( rc ) ); - goto err_init; - } + cms_digest ( cms, part, data, len, digest_out ); /* Verify digest */ - if ( ( rc = pubkey_verify ( pubkey, ctx, digest, digest_out, - info->signature, - info->signature_len ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p signature verification failed: %s\n", - sig, info, strerror ( rc ) ); - goto err_verify; + if ( ( rc = pubkey_verify ( pubkey, key, digest, digest_out, + value->data, value->len ) ) != 0 ) { + DBGC ( cms, "CMS %p/%p signature verification failed: %s\n", + cms, part, strerror ( rc ) ); + return rc; } - err_verify: - pubkey_final ( pubkey, ctx ); - err_init: - return rc; + return 0; } /** - * Verify CMS signature signer information + * Verify CMS message signer * - * @v sig CMS signature - * @v info Signer information + * @v cms CMS message + * @v part Participant information * @v data Signed data * @v len Length of signed data * @v time Time at which to validate certificates @@ -625,42 +799,42 @@ static int cms_verify_digest ( struct cms_signature *sig, * @v root Root certificate list, or NULL to use default * @ret rc Return status code */ -static int cms_verify_signer_info ( struct cms_signature *sig, - struct cms_signer_info *info, - userptr_t data, size_t len, - time_t time, struct x509_chain *store, - struct x509_root *root ) { +static int cms_verify_signer ( struct cms_message *cms, + struct cms_participant *part, + userptr_t data, size_t len, + time_t time, struct x509_chain *store, + struct x509_root *root ) { struct x509_certificate *cert; int rc; /* Validate certificate chain */ - if ( ( rc = x509_validate_chain ( info->chain, time, store, + if ( ( rc = x509_validate_chain ( part->chain, time, store, root ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not validate chain: %s\n", - sig, info, strerror ( rc ) ); + DBGC ( cms, "CMS %p/%p could not validate chain: %s\n", + cms, part, strerror ( rc ) ); return rc; } /* Extract code-signing certificate */ - cert = x509_first ( info->chain ); + cert = x509_first ( part->chain ); assert ( cert != NULL ); /* Check that certificate can create digital signatures */ if ( ! ( cert->extensions.usage.bits & X509_DIGITAL_SIGNATURE ) ) { - DBGC ( sig, "CMS %p/%p certificate cannot create signatures\n", - sig, info ); + DBGC ( cms, "CMS %p/%p certificate cannot create signatures\n", + cms, part ); return -EACCES_NON_SIGNING; } /* Check that certificate can sign code */ if ( ! ( cert->extensions.ext_usage.bits & X509_CODE_SIGNING ) ) { - DBGC ( sig, "CMS %p/%p certificate is not code-signing\n", - sig, info ); + DBGC ( cms, "CMS %p/%p certificate is not code-signing\n", + cms, part ); return -EACCES_NON_CODE_SIGNING; } /* Verify digest */ - if ( ( rc = cms_verify_digest ( sig, info, cert, data, len ) ) != 0 ) + if ( ( rc = cms_verify_digest ( cms, part, cert, data, len ) ) != 0 ) return rc; return 0; @@ -669,30 +843,37 @@ static int cms_verify_signer_info ( struct cms_signature *sig, /** * Verify CMS signature * - * @v sig CMS signature - * @v data Signed data - * @v len Length of signed data + * @v cms CMS message + * @v image Signed image * @v name Required common name, or NULL to check all signatures * @v time Time at which to validate certificates * @v store Certificate store, or NULL to use default * @v root Root certificate list, or NULL to use default * @ret rc Return status code */ -int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len, +int cms_verify ( struct cms_message *cms, struct image *image, const char *name, time_t time, struct x509_chain *store, struct x509_root *root ) { - struct cms_signer_info *info; + struct cms_participant *part; struct x509_certificate *cert; int count = 0; int rc; - /* Verify using all signerInfos */ - list_for_each_entry ( info, &sig->info, list ) { - cert = x509_first ( info->chain ); + /* Mark image as untrusted */ + image_untrust ( image ); + + /* Sanity check */ + if ( ! cms_is_signature ( cms ) ) + return -ENOTTY; + + /* Verify using all signers */ + list_for_each_entry ( part, &cms->participants, list ) { + cert = x509_first ( part->chain ); if ( name && ( x509_check_name ( cert, name ) != 0 ) ) continue; - if ( ( rc = cms_verify_signer_info ( sig, info, data, len, time, - store, root ) ) != 0 ) + if ( ( rc = cms_verify_signer ( cms, part, image->data, + image->len, time, store, + root ) ) != 0 ) return rc; count++; } @@ -700,14 +881,329 @@ int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len, /* Check that we have verified at least one signature */ if ( count == 0 ) { if ( name ) { - DBGC ( sig, "CMS %p had no signatures matching name " - "%s\n", sig, name ); + DBGC ( cms, "CMS %p had no signatures matching name " + "%s\n", cms, name ); return -EACCES_WRONG_NAME; } else { - DBGC ( sig, "CMS %p had no signatures\n", sig ); + DBGC ( cms, "CMS %p had no signatures\n", cms ); return -EACCES_NO_SIGNATURES; } } + /* Mark image as trusted */ + image_trust ( image ); + + return 0; +} + +/** + * Identify CMS recipient corresponding to private key + * + * @v cms CMS message + * @v private_key Private key + * @ret part Participant information, or NULL if not found + */ +static struct cms_participant * +cms_recipient ( struct cms_message *cms, struct private_key *private_key ) { + struct cms_participant *part; + struct x509_certificate *cert; + + /* Identify certificate (if any) for which we have a private key */ + cert = x509_find_key ( NULL, private_key ); + if ( ! cert ) + return NULL; + + /* Identify corresponding recipient, if any */ + list_for_each_entry ( part, &cms->participants, list ) { + if ( cert == x509_first ( part->chain ) ) + return part; + } + + return NULL; +} + +/** + * Set CMS cipher key + * + * @v cms CMS message + * @v part Participant information + * @v private_key Private key + * @v ctx Cipher context + * @ret rc Return status code + */ +static int cms_cipher_key ( struct cms_message *cms, + struct cms_participant *part, + struct private_key *private_key, void *ctx ) { + struct cipher_algorithm *cipher = cms->cipher; + struct pubkey_algorithm *pubkey = part->pubkey; + const struct asn1_cursor *key = privkey_cursor ( private_key ); + const struct asn1_cursor *value = &part->value; + size_t max_len = pubkey_max_len ( pubkey, key ); + uint8_t cipher_key[max_len]; + int len; + int rc; + + /* Decrypt cipher key */ + len = pubkey_decrypt ( pubkey, key, value->data, value->len, + cipher_key ); + if ( len < 0 ) { + rc = len; + DBGC ( cms, "CMS %p/%p could not decrypt cipher key: %s\n", + cms, part, strerror ( rc ) ); + DBGC_HDA ( cms, 0, value->data, value->len ); + return rc; + } + DBGC ( cms, "CMS %p/%p cipher key:\n", cms, part ); + DBGC_HDA ( cms, 0, cipher_key, len ); + + /* Set cipher key */ + if ( ( rc = cipher_setkey ( cipher, ctx, cipher_key, len ) ) != 0 ) { + DBGC ( cms, "CMS %p could not set cipher key: %s\n", + cms, strerror ( rc ) ); + return rc; + } + + /* Set cipher initialization vector */ + cipher_setiv ( cipher, ctx, cms->iv.data, cms->iv.len ); + if ( cms->iv.len ) { + DBGC ( cms, "CMS %p cipher IV:\n", cms ); + DBGC_HDA ( cms, 0, cms->iv.data, cms->iv.len ); + } + return 0; } + +/** + * Initialise cipher for CMS decryption + * + * @v cms CMS message + * @v private_key Private key + * @v ctx Cipher context + * @ret rc Return status code + */ +static int cms_cipher ( struct cms_message *cms, + struct private_key *private_key, void *ctx ) { + struct cms_participant *part; + int rc; + + /* Identify a usable recipient */ + part = cms_recipient ( cms, private_key ); + if ( ! part ) { + DBGC ( cms, "CMS %p had no usable recipients\n", cms ); + return -EACCES_NO_RECIPIENTS; + } + + /* Decrypt and set cipher key */ + if ( ( rc = cms_cipher_key ( cms, part, private_key, ctx ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Check CMS padding + * + * @v cms CMS message + * @v data Final block + * @v len Final block length + * @ret len Padding length, or negative error + */ +static int cms_verify_padding ( struct cms_message *cms, const void *data, + size_t len ) { + struct cipher_algorithm *cipher = cms->cipher; + const uint8_t *pad; + size_t pad_len; + unsigned int i; + + /* Non-block ciphers do not use padding */ + if ( ! is_block_cipher ( cipher ) ) + return 0; + + /* Block padding can never produce an empty file */ + if ( len == 0 ) { + DBGC ( cms, "CMS %p invalid empty padding\n", cms ); + return -EACCES_PAD; + } + + /* Sanity check */ + assert ( len >= cipher->blocksize ); + + /* Extract and verify padding */ + pad = ( data + len - 1 ); + pad_len = *pad; + if ( ( pad_len == 0 ) || ( pad_len > len ) ) { + DBGC ( cms, "CMS %p invalid padding length %zd\n", + cms, pad_len ); + return -EACCES_PAD; + } + for ( i = 0 ; i < pad_len ; i++ ) { + if ( *(pad--) != pad_len ) { + DBGC ( cms, "CMS %p invalid padding\n", cms ); + DBGC_HDA ( cms, 0, ( data + len - pad_len ), pad_len ); + return -EACCES_PAD; + } + } + + return pad_len; +} + +/** + * Decrypt CMS message + * + * @v cms CMS message + * @v image Image to decrypt + * @v name Decrypted image name, or NULL to use default + * @v private_key Private key + * @ret rc Return status code + */ +int cms_decrypt ( struct cms_message *cms, struct image *image, + const char *name, struct private_key *private_key ) { + struct cipher_algorithm *cipher = cms->cipher; + const unsigned int original_flags = image->flags; + size_t offset; + size_t remaining; + size_t frag_len; + int pad_len; + void *tmp; + void *ctx; + void *ctxdup; + void *auth; + int rc; + + /* Sanity checks */ + if ( ! cipher ) { + rc = -ENOTTY; + goto err_no_cipher; + } + + /* Check block size */ + if ( ( image->len & ( cipher->blocksize - 1 ) ) != 0 ) { + DBGC ( cms, "CMS %p invalid length %zd\n", cms, image->len ); + rc = -EACCES_LEN; + goto err_blocksize; + } + + /* Allocate temporary working space */ + tmp = malloc ( CMS_DECRYPT_BLKSZ + ( 2 * cipher->ctxsize ) + + cipher->authsize ); + if ( ! tmp ) { + rc = -ENOMEM; + goto err_alloc; + } + ctx = ( tmp + CMS_DECRYPT_BLKSZ ); + ctxdup = ( ctx + cipher->ctxsize ); + auth = ( ctxdup + cipher->ctxsize ); + + /* Initialise cipher */ + if ( ( rc = cms_cipher ( cms, private_key, ctx ) ) != 0 ) + goto err_cipher; + + /* Duplicate cipher context for potential reencryption on error */ + memcpy ( ctxdup, ctx, cipher->ctxsize ); + + /* Clear trusted flag before modifying image */ + image_untrust ( image ); + + /* Temporarily unregister image, if applicable */ + if ( original_flags & IMAGE_REGISTERED ) { + image_get ( image ); + unregister_image ( image ); + } + + /* Decrypt one block at a time */ + offset = 0; + remaining = image->len; + frag_len = 0; + while ( remaining ) { + + /* Calculate fragment length */ + frag_len = remaining; + if ( frag_len > CMS_DECRYPT_BLKSZ ) + frag_len = CMS_DECRYPT_BLKSZ; + + /* Decrypt fragment */ + copy_from_user ( tmp, image->data, offset, frag_len ); + cipher_decrypt ( cipher, ctx, tmp, tmp, frag_len ); + + /* Overwrite all but the final fragment */ + if ( remaining > frag_len ) + copy_to_user ( image->data, offset, tmp, frag_len ); + + /* Move to next block */ + remaining -= frag_len; + offset += frag_len; + } + + /* Check authentication tag, if applicable */ + cipher_auth ( cipher, ctx, auth ); + if ( ( cms->mac.len != cipher->authsize ) || + ( memcmp ( cms->mac.data, auth, cipher->authsize ) != 0 ) ) { + DBGC ( cms, "CMS %p invalid authentication tag\n", cms ); + DBGC_HDA ( cms, 0, auth, cipher->authsize ); + rc = -EACCES_MAC; + goto err_auth; + } + + /* Check block padding, if applicable */ + if ( ( pad_len = cms_verify_padding ( cms, tmp, frag_len ) ) < 0 ) { + rc = pad_len; + goto err_pad; + } + + /* Update image name. Do this as the last possible failure, so + * that we do not have to include any error-handling code path + * to restore the original image name (which may itself fail). + */ + if ( name ) { + if ( ( rc = image_set_name ( image, name ) ) != 0 ) + goto err_set_name; + } else { + image_strip_suffix ( image ); + } + + /* Overwrite final fragment and strip block padding. Do this + * only once no further failure paths exist, so that we do not + * have to include include any error-handling code path to + * reconstruct the block padding. + */ + copy_to_user ( image->data, ( offset - frag_len ), tmp, frag_len ); + image->len -= pad_len; + + /* Clear image type and re-register image, if applicable */ + image->type = NULL; + if ( original_flags & IMAGE_REGISTERED ) { + register_image ( image ); + image_put ( image ); + } + + /* Free temporary working space */ + free ( tmp ); + + return 0; + + err_set_name: + err_pad: + err_auth: + /* Reencrypt all overwritten fragments. This can be done + * since we have deliberately not overwritten the final + * fragment containing the potentially invalid (and therefore + * unreproducible) block padding. + */ + remaining = ( offset - frag_len ); + for ( offset = 0 ; offset < remaining ; offset += CMS_DECRYPT_BLKSZ ) { + copy_from_user ( tmp, image->data, offset, CMS_DECRYPT_BLKSZ ); + cipher_encrypt ( cipher, ctxdup, tmp, tmp, CMS_DECRYPT_BLKSZ ); + copy_to_user ( image->data, offset, tmp, CMS_DECRYPT_BLKSZ ); + } + if ( original_flags & IMAGE_REGISTERED ) { + register_image ( image ); /* Cannot fail on re-registration */ + image_put ( image ); + } + image->flags = original_flags; + err_cipher: + free ( tmp ); + err_alloc: + err_blocksize: + err_no_cipher: + return rc; +} diff --git a/src/crypto/crypto_null.c b/src/crypto/crypto_null.c index 0ad463c..d5863f9 100644 --- a/src/crypto/crypto_null.c +++ b/src/crypto/crypto_null.c @@ -93,34 +93,31 @@ struct cipher_algorithm cipher_null = { .auth = cipher_null_auth, }; -int pubkey_null_init ( void *ctx __unused, const void *key __unused, - size_t key_len __unused ) { +size_t pubkey_null_max_len ( const struct asn1_cursor *key __unused ) { return 0; } -size_t pubkey_null_max_len ( void *ctx __unused ) { - return 0; -} - -int pubkey_null_encrypt ( void *ctx __unused, const void *plaintext __unused, +int pubkey_null_encrypt ( const struct asn1_cursor *key __unused, + const void *plaintext __unused, size_t plaintext_len __unused, void *ciphertext __unused ) { return 0; } -int pubkey_null_decrypt ( void *ctx __unused, const void *ciphertext __unused, +int pubkey_null_decrypt ( const struct asn1_cursor *key __unused, + const void *ciphertext __unused, size_t ciphertext_len __unused, void *plaintext __unused ) { return 0; } -int pubkey_null_sign ( void *ctx __unused, +int pubkey_null_sign ( const struct asn1_cursor *key __unused, struct digest_algorithm *digest __unused, const void *value __unused, void *signature __unused ) { return 0; } -int pubkey_null_verify ( void *ctx __unused, +int pubkey_null_verify ( const struct asn1_cursor *key __unused, struct digest_algorithm *digest __unused, const void *value __unused, const void *signature __unused , @@ -128,18 +125,11 @@ int pubkey_null_verify ( void *ctx __unused, return 0; } -void pubkey_null_final ( void *ctx __unused ) { - /* Do nothing */ -} - struct pubkey_algorithm pubkey_null = { .name = "null", - .ctxsize = 0, - .init = pubkey_null_init, .max_len = pubkey_null_max_len, .encrypt = pubkey_null_encrypt, .decrypt = pubkey_null_decrypt, .sign = pubkey_null_sign, .verify = pubkey_null_verify, - .final = pubkey_null_final, }; diff --git a/src/crypto/mishmash/oid_aes_cbc.c b/src/crypto/mishmash/oid_aes_cbc.c new file mode 100644 index 0000000..b5f7165 --- /dev/null +++ b/src/crypto/mishmash/oid_aes_cbc.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 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 (at your option) 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 <ipxe/aes.h> +#include <ipxe/asn1.h> + +/** "aes128-cbc" object identifier */ +static uint8_t oid_aes_128_cbc[] = { ASN1_OID_AES128_CBC }; + +/** "aes192-cbc" object identifier */ +static uint8_t oid_aes_192_cbc[] = { ASN1_OID_AES192_CBC }; + +/** "aes256-cbc" object identifier */ +static uint8_t oid_aes_256_cbc[] = { ASN1_OID_AES256_CBC }; + +/** "aes128-cbc" OID-identified algorithm */ +struct asn1_algorithm aes_128_cbc_algorithm __asn1_algorithm = { + .name = "aes128-cbc", + .cipher = &aes_cbc_algorithm, + .oid = ASN1_CURSOR ( oid_aes_128_cbc ), + .parse = asn1_parse_cbc, +}; + +/** "aes192-cbc" OID-identified algorithm */ +struct asn1_algorithm aes_192_cbc_algorithm __asn1_algorithm = { + .name = "aes192-cbc", + .cipher = &aes_cbc_algorithm, + .oid = ASN1_CURSOR ( oid_aes_192_cbc ), + .parse = asn1_parse_cbc, +}; + +/** "aes256-cbc" OID-identified algorithm */ +struct asn1_algorithm aes_256_cbc_algorithm __asn1_algorithm = { + .name = "aes256-cbc", + .cipher = &aes_cbc_algorithm, + .oid = ASN1_CURSOR ( oid_aes_256_cbc ), + .parse = asn1_parse_cbc, +}; diff --git a/src/crypto/mishmash/oid_aes_gcm.c b/src/crypto/mishmash/oid_aes_gcm.c new file mode 100644 index 0000000..af1432d --- /dev/null +++ b/src/crypto/mishmash/oid_aes_gcm.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 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 (at your option) 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 <ipxe/aes.h> +#include <ipxe/asn1.h> + +/** "aes128-gcm" object identifier */ +static uint8_t oid_aes_128_gcm[] = { ASN1_OID_AES128_GCM }; + +/** "aes192-gcm" object identifier */ +static uint8_t oid_aes_192_gcm[] = { ASN1_OID_AES192_GCM }; + +/** "aes256-gcm" object identifier */ +static uint8_t oid_aes_256_gcm[] = { ASN1_OID_AES256_GCM }; + +/** "aes128-gcm" OID-identified algorithm */ +struct asn1_algorithm aes_128_gcm_algorithm __asn1_algorithm = { + .name = "aes128-gcm", + .cipher = &aes_gcm_algorithm, + .oid = ASN1_CURSOR ( oid_aes_128_gcm ), + .parse = asn1_parse_gcm, +}; + +/** "aes192-gcm" OID-identified algorithm */ +struct asn1_algorithm aes_192_gcm_algorithm __asn1_algorithm = { + .name = "aes192-gcm", + .cipher = &aes_gcm_algorithm, + .oid = ASN1_CURSOR ( oid_aes_192_gcm ), + .parse = asn1_parse_gcm, +}; + +/** "aes256-gcm" OID-identified algorithm */ +struct asn1_algorithm aes_256_gcm_algorithm __asn1_algorithm = { + .name = "aes256-gcm", + .cipher = &aes_gcm_algorithm, + .oid = ASN1_CURSOR ( oid_aes_256_gcm ), + .parse = asn1_parse_gcm, +}; diff --git a/src/crypto/ocsp.c b/src/crypto/ocsp.c index cc957b4..e65f718 100644 --- a/src/crypto/ocsp.c +++ b/src/crypto/ocsp.c @@ -844,10 +844,9 @@ static int ocsp_check_signature ( struct ocsp_check *ocsp, struct ocsp_response *response = &ocsp->response; struct digest_algorithm *digest = response->algorithm->digest; struct pubkey_algorithm *pubkey = response->algorithm->pubkey; - struct x509_public_key *public_key = &signer->subject.public_key; + struct asn1_cursor *key = &signer->subject.public_key.raw; uint8_t digest_ctx[ digest->ctxsize ]; uint8_t digest_out[ digest->digestsize ]; - uint8_t pubkey_ctx[ pubkey->ctxsize ]; int rc; /* Generate digest */ @@ -856,30 +855,18 @@ static int ocsp_check_signature ( struct ocsp_check *ocsp, response->tbs.len ); digest_final ( digest, digest_ctx, digest_out ); - /* Initialise public-key algorithm */ - if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data, - public_key->raw.len ) ) != 0 ) { - DBGC ( ocsp, "OCSP %p \"%s\" could not initialise public key: " - "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); - goto err_init; - } - /* Verify digest */ - if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out, + if ( ( rc = pubkey_verify ( pubkey, key, digest, digest_out, response->signature.data, response->signature.len ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" signature verification failed: " "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); - goto err_verify; + return rc; } DBGC2 ( ocsp, "OCSP %p \"%s\" signature is correct\n", ocsp, x509_name ( ocsp->cert ) ); - - err_verify: - pubkey_final ( pubkey, pubkey_ctx ); - err_init: - return rc; + return 0; } /** diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index 16c67d8..19472c1 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -47,6 +47,28 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define EINFO_EACCES_VERIFY \ __einfo_uniqify ( EINFO_EACCES, 0x01, "RSA signature incorrect" ) +/** An RSA context */ +struct rsa_context { + /** Allocated memory */ + void *dynamic; + /** Modulus */ + bigint_element_t *modulus0; + /** Modulus size */ + unsigned int size; + /** Modulus length */ + size_t max_len; + /** Exponent */ + bigint_element_t *exponent0; + /** Exponent size */ + unsigned int exponent_size; + /** Input buffer */ + bigint_element_t *input0; + /** Output buffer */ + bigint_element_t *output0; + /** Temporary working space for modular exponentiation */ + void *tmp; +}; + /** * Identify RSA prefix * @@ -69,10 +91,9 @@ rsa_find_prefix ( struct digest_algorithm *digest ) { * * @v context RSA context */ -static void rsa_free ( struct rsa_context *context ) { +static inline void rsa_free ( struct rsa_context *context ) { free ( context->dynamic ); - context->dynamic = NULL; } /** @@ -98,9 +119,6 @@ static int rsa_alloc ( struct rsa_context *context, size_t modulus_len, uint8_t tmp[tmp_len]; } __attribute__ (( packed )) *dynamic; - /* Free any existing dynamic storage */ - rsa_free ( context ); - /* Allocate dynamic storage */ dynamic = malloc ( sizeof ( *dynamic ) ); if ( ! dynamic ) @@ -231,29 +249,23 @@ static int rsa_parse_mod_exp ( struct asn1_cursor *modulus, /** * Initialise RSA cipher * - * @v ctx RSA context + * @v context RSA context * @v key Key - * @v key_len Length of key * @ret rc Return status code */ -static int rsa_init ( void *ctx, const void *key, size_t key_len ) { - struct rsa_context *context = ctx; +static int rsa_init ( struct rsa_context *context, + const struct asn1_cursor *key ) { struct asn1_cursor modulus; struct asn1_cursor exponent; - struct asn1_cursor cursor; int rc; /* Initialise context */ memset ( context, 0, sizeof ( *context ) ); - /* Initialise cursor */ - cursor.data = key; - cursor.len = key_len; - /* Parse modulus and exponent */ - if ( ( rc = rsa_parse_mod_exp ( &modulus, &exponent, &cursor ) ) != 0 ){ + if ( ( rc = rsa_parse_mod_exp ( &modulus, &exponent, key ) ) != 0 ){ DBGC ( context, "RSA %p invalid modulus/exponent:\n", context ); - DBGC_HDA ( context, 0, cursor.data, cursor.len ); + DBGC_HDA ( context, 0, key->data, key->len ); goto err_parse; } @@ -283,13 +295,22 @@ static int rsa_init ( void *ctx, const void *key, size_t key_len ) { /** * Calculate RSA maximum output length * - * @v ctx RSA context + * @v key Key * @ret max_len Maximum output length */ -static size_t rsa_max_len ( void *ctx ) { - struct rsa_context *context = ctx; +static size_t rsa_max_len ( const struct asn1_cursor *key ) { + struct asn1_cursor modulus; + struct asn1_cursor exponent; + int rc; + + /* Parse moduli and exponents */ + if ( ( rc = rsa_parse_mod_exp ( &modulus, &exponent, key ) ) != 0 ) { + /* Return a zero maximum length on error */ + return 0; + } - return context->max_len; + /* Output length can never exceed modulus length */ + return modulus.len; } /** @@ -320,111 +341,147 @@ static void rsa_cipher ( struct rsa_context *context, /** * Encrypt using RSA * - * @v ctx RSA context + * @v key Key * @v plaintext Plaintext * @v plaintext_len Length of plaintext * @v ciphertext Ciphertext * @ret ciphertext_len Length of ciphertext, or negative error */ -static int rsa_encrypt ( void *ctx, const void *plaintext, +static int rsa_encrypt ( const struct asn1_cursor *key, const void *plaintext, size_t plaintext_len, void *ciphertext ) { - struct rsa_context *context = ctx; + struct rsa_context context; void *temp; uint8_t *encoded; - size_t max_len = ( context->max_len - 11 ); - size_t random_nz_len = ( max_len - plaintext_len + 8 ); + size_t max_len; + size_t random_nz_len; int rc; + DBGC ( &context, "RSA %p encrypting:\n", &context ); + DBGC_HDA ( &context, 0, plaintext, plaintext_len ); + + /* Initialise context */ + if ( ( rc = rsa_init ( &context, key ) ) != 0 ) + goto err_init; + + /* Calculate lengths */ + max_len = ( context.max_len - 11 ); + random_nz_len = ( max_len - plaintext_len + 8 ); + /* Sanity check */ if ( plaintext_len > max_len ) { - DBGC ( context, "RSA %p plaintext too long (%zd bytes, max " - "%zd)\n", context, plaintext_len, max_len ); - return -ERANGE; + DBGC ( &context, "RSA %p plaintext too long (%zd bytes, max " + "%zd)\n", &context, plaintext_len, max_len ); + rc = -ERANGE; + goto err_sanity; } - DBGC ( context, "RSA %p encrypting:\n", context ); - DBGC_HDA ( context, 0, plaintext, plaintext_len ); /* Construct encoded message (using the big integer output * buffer as temporary storage) */ - temp = context->output0; + temp = context.output0; encoded = temp; encoded[0] = 0x00; encoded[1] = 0x02; if ( ( rc = get_random_nz ( &encoded[2], random_nz_len ) ) != 0 ) { - DBGC ( context, "RSA %p could not generate random data: %s\n", - context, strerror ( rc ) ); - return rc; + DBGC ( &context, "RSA %p could not generate random data: %s\n", + &context, strerror ( rc ) ); + goto err_random; } encoded[ 2 + random_nz_len ] = 0x00; - memcpy ( &encoded[ context->max_len - plaintext_len ], + memcpy ( &encoded[ context.max_len - plaintext_len ], plaintext, plaintext_len ); /* Encipher the encoded message */ - rsa_cipher ( context, encoded, ciphertext ); - DBGC ( context, "RSA %p encrypted:\n", context ); - DBGC_HDA ( context, 0, ciphertext, context->max_len ); + rsa_cipher ( &context, encoded, ciphertext ); + DBGC ( &context, "RSA %p encrypted:\n", &context ); + DBGC_HDA ( &context, 0, ciphertext, context.max_len ); - return context->max_len; + /* Free context */ + rsa_free ( &context ); + + return context.max_len; + + err_random: + err_sanity: + rsa_free ( &context ); + err_init: + return rc; } /** * Decrypt using RSA * - * @v ctx RSA context + * @v key Key * @v ciphertext Ciphertext * @v ciphertext_len Ciphertext length * @v plaintext Plaintext * @ret plaintext_len Plaintext length, or negative error */ -static int rsa_decrypt ( void *ctx, const void *ciphertext, +static int rsa_decrypt ( const struct asn1_cursor *key, const void *ciphertext, size_t ciphertext_len, void *plaintext ) { - struct rsa_context *context = ctx; + struct rsa_context context; void *temp; uint8_t *encoded; uint8_t *end; uint8_t *zero; uint8_t *start; size_t plaintext_len; + int rc; + + DBGC ( &context, "RSA %p decrypting:\n", &context ); + DBGC_HDA ( &context, 0, ciphertext, ciphertext_len ); + + /* Initialise context */ + if ( ( rc = rsa_init ( &context, key ) ) != 0 ) + goto err_init; /* Sanity check */ - if ( ciphertext_len != context->max_len ) { - DBGC ( context, "RSA %p ciphertext incorrect length (%zd " + if ( ciphertext_len != context.max_len ) { + DBGC ( &context, "RSA %p ciphertext incorrect length (%zd " "bytes, should be %zd)\n", - context, ciphertext_len, context->max_len ); - return -ERANGE; + &context, ciphertext_len, context.max_len ); + rc = -ERANGE; + goto err_sanity; } - DBGC ( context, "RSA %p decrypting:\n", context ); - DBGC_HDA ( context, 0, ciphertext, ciphertext_len ); /* Decipher the message (using the big integer input buffer as * temporary storage) */ - temp = context->input0; + temp = context.input0; encoded = temp; - rsa_cipher ( context, ciphertext, encoded ); + rsa_cipher ( &context, ciphertext, encoded ); /* Parse the message */ - end = ( encoded + context->max_len ); - if ( ( encoded[0] != 0x00 ) || ( encoded[1] != 0x02 ) ) - goto invalid; + end = ( encoded + context.max_len ); + if ( ( encoded[0] != 0x00 ) || ( encoded[1] != 0x02 ) ) { + rc = -EINVAL; + goto err_invalid; + } zero = memchr ( &encoded[2], 0, ( end - &encoded[2] ) ); - if ( ! zero ) - goto invalid; + if ( ! zero ) { + rc = -EINVAL; + goto err_invalid; + } start = ( zero + 1 ); plaintext_len = ( end - start ); /* Copy out message */ memcpy ( plaintext, start, plaintext_len ); - DBGC ( context, "RSA %p decrypted:\n", context ); - DBGC_HDA ( context, 0, plaintext, plaintext_len ); + DBGC ( &context, "RSA %p decrypted:\n", &context ); + DBGC_HDA ( &context, 0, plaintext, plaintext_len ); + + /* Free context */ + rsa_free ( &context ); return plaintext_len; - invalid: - DBGC ( context, "RSA %p invalid decrypted message:\n", context ); - DBGC_HDA ( context, 0, encoded, context->max_len ); - return -EINVAL; + err_invalid: + DBGC ( &context, "RSA %p invalid decrypted message:\n", &context ); + DBGC_HDA ( &context, 0, encoded, context.max_len ); + err_sanity: + rsa_free ( &context ); + err_init: + return rc; } /** @@ -458,9 +515,9 @@ static int rsa_encode_digest ( struct rsa_context *context, /* Sanity check */ max_len = ( context->max_len - 11 ); if ( digestinfo_len > max_len ) { - DBGC ( context, "RSA %p %s digestInfo too long (%zd bytes, max" - "%zd)\n", - context, digest->name, digestinfo_len, max_len ); + DBGC ( context, "RSA %p %s digestInfo too long (%zd bytes, " + "max %zd)\n", context, digest->name, digestinfo_len, + max_len ); return -ERANGE; } DBGC ( context, "RSA %p encoding %s digest:\n", @@ -488,137 +545,148 @@ static int rsa_encode_digest ( struct rsa_context *context, /** * Sign digest value using RSA * - * @v ctx RSA context + * @v key Key * @v digest Digest algorithm * @v value Digest value * @v signature Signature * @ret signature_len Signature length, or negative error */ -static int rsa_sign ( void *ctx, struct digest_algorithm *digest, - const void *value, void *signature ) { - struct rsa_context *context = ctx; +static int rsa_sign ( const struct asn1_cursor *key, + struct digest_algorithm *digest, const void *value, + void *signature ) { + struct rsa_context context; void *temp; int rc; - DBGC ( context, "RSA %p signing %s digest:\n", context, digest->name ); - DBGC_HDA ( context, 0, value, digest->digestsize ); + DBGC ( &context, "RSA %p signing %s digest:\n", + &context, digest->name ); + DBGC_HDA ( &context, 0, value, digest->digestsize ); + + /* Initialise context */ + if ( ( rc = rsa_init ( &context, key ) ) != 0 ) + goto err_init; /* Encode digest (using the big integer output buffer as * temporary storage) */ - temp = context->output0; - if ( ( rc = rsa_encode_digest ( context, digest, value, temp ) ) != 0 ) - return rc; + temp = context.output0; + if ( ( rc = rsa_encode_digest ( &context, digest, value, temp ) ) != 0 ) + goto err_encode; /* Encipher the encoded digest */ - rsa_cipher ( context, temp, signature ); - DBGC ( context, "RSA %p signed %s digest:\n", context, digest->name ); - DBGC_HDA ( context, 0, signature, context->max_len ); + rsa_cipher ( &context, temp, signature ); + DBGC ( &context, "RSA %p signed %s digest:\n", &context, digest->name ); + DBGC_HDA ( &context, 0, signature, context.max_len ); + + /* Free context */ + rsa_free ( &context ); - return context->max_len; + return context.max_len; + + err_encode: + rsa_free ( &context ); + err_init: + return rc; } /** * Verify signed digest value using RSA * - * @v ctx RSA context + * @v key Key * @v digest Digest algorithm * @v value Digest value * @v signature Signature * @v signature_len Signature length * @ret rc Return status code */ -static int rsa_verify ( void *ctx, struct digest_algorithm *digest, - const void *value, const void *signature, - size_t signature_len ) { - struct rsa_context *context = ctx; +static int rsa_verify ( const struct asn1_cursor *key, + struct digest_algorithm *digest, const void *value, + const void *signature, size_t signature_len ) { + struct rsa_context context; void *temp; void *expected; void *actual; int rc; + DBGC ( &context, "RSA %p verifying %s digest:\n", + &context, digest->name ); + DBGC_HDA ( &context, 0, value, digest->digestsize ); + DBGC_HDA ( &context, 0, signature, signature_len ); + + /* Initialise context */ + if ( ( rc = rsa_init ( &context, key ) ) != 0 ) + goto err_init; + /* Sanity check */ - if ( signature_len != context->max_len ) { - DBGC ( context, "RSA %p signature incorrect length (%zd " + if ( signature_len != context.max_len ) { + DBGC ( &context, "RSA %p signature incorrect length (%zd " "bytes, should be %zd)\n", - context, signature_len, context->max_len ); - return -ERANGE; + &context, signature_len, context.max_len ); + rc = -ERANGE; + goto err_sanity; } - DBGC ( context, "RSA %p verifying %s digest:\n", - context, digest->name ); - DBGC_HDA ( context, 0, value, digest->digestsize ); - DBGC_HDA ( context, 0, signature, signature_len ); /* Decipher the signature (using the big integer input buffer * as temporary storage) */ - temp = context->input0; + temp = context.input0; expected = temp; - rsa_cipher ( context, signature, expected ); - DBGC ( context, "RSA %p deciphered signature:\n", context ); - DBGC_HDA ( context, 0, expected, context->max_len ); + rsa_cipher ( &context, signature, expected ); + DBGC ( &context, "RSA %p deciphered signature:\n", &context ); + DBGC_HDA ( &context, 0, expected, context.max_len ); /* Encode digest (using the big integer output buffer as * temporary storage) */ - temp = context->output0; + temp = context.output0; actual = temp; - if ( ( rc = rsa_encode_digest ( context, digest, value, actual ) ) !=0 ) - return rc; + if ( ( rc = rsa_encode_digest ( &context, digest, value, + actual ) ) != 0 ) + goto err_encode; /* Verify the signature */ - if ( memcmp ( actual, expected, context->max_len ) != 0 ) { - DBGC ( context, "RSA %p signature verification failed\n", - context ); - return -EACCES_VERIFY; + if ( memcmp ( actual, expected, context.max_len ) != 0 ) { + DBGC ( &context, "RSA %p signature verification failed\n", + &context ); + rc = -EACCES_VERIFY; + goto err_verify; } - DBGC ( context, "RSA %p signature verified successfully\n", context ); - return 0; -} + /* Free context */ + rsa_free ( &context ); -/** - * Finalise RSA cipher - * - * @v ctx RSA context - */ -static void rsa_final ( void *ctx ) { - struct rsa_context *context = ctx; + DBGC ( &context, "RSA %p signature verified successfully\n", &context ); + return 0; - rsa_free ( context ); + err_verify: + err_encode: + err_sanity: + rsa_free ( &context ); + err_init: + return rc; } /** * Check for matching RSA public/private key pair * * @v private_key Private key - * @v private_key_len Private key length * @v public_key Public key - * @v public_key_len Public key length * @ret rc Return status code */ -static int rsa_match ( const void *private_key, size_t private_key_len, - const void *public_key, size_t public_key_len ) { +static int rsa_match ( const struct asn1_cursor *private_key, + const struct asn1_cursor *public_key ) { struct asn1_cursor private_modulus; struct asn1_cursor private_exponent; - struct asn1_cursor private_cursor; struct asn1_cursor public_modulus; struct asn1_cursor public_exponent; - struct asn1_cursor public_cursor; int rc; - /* Initialise cursors */ - private_cursor.data = private_key; - private_cursor.len = private_key_len; - public_cursor.data = public_key; - public_cursor.len = public_key_len; - /* Parse moduli and exponents */ if ( ( rc = rsa_parse_mod_exp ( &private_modulus, &private_exponent, - &private_cursor ) ) != 0 ) + private_key ) ) != 0 ) return rc; if ( ( rc = rsa_parse_mod_exp ( &public_modulus, &public_exponent, - &public_cursor ) ) != 0 ) + public_key ) ) != 0 ) return rc; /* Compare moduli */ @@ -631,14 +699,11 @@ static int rsa_match ( const void *private_key, size_t private_key_len, /** RSA public-key algorithm */ struct pubkey_algorithm rsa_algorithm = { .name = "rsa", - .ctxsize = RSA_CTX_SIZE, - .init = rsa_init, .max_len = rsa_max_len, .encrypt = rsa_encrypt, .decrypt = rsa_decrypt, .sign = rsa_sign, .verify = rsa_verify, - .final = rsa_final, .match = rsa_match, }; diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 9231809..4101c80 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -38,6 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/rsa.h> #include <ipxe/rootcert.h> #include <ipxe/certstore.h> +#include <ipxe/privkey.h> #include <ipxe/socket.h> #include <ipxe/in.h> #include <ipxe/image.h> @@ -1078,7 +1079,7 @@ int x509_certificate ( const void *data, size_t len, asn1_shrink_any ( &cursor ); /* Return stored certificate, if present */ - if ( ( *cert = certstore_find ( &cursor ) ) != NULL ) { + if ( ( *cert = x509_find ( NULL, &cursor ) ) != NULL ) { /* Add caller's reference */ x509_get ( *cert ); @@ -1124,7 +1125,6 @@ static int x509_check_signature ( struct x509_certificate *cert, struct pubkey_algorithm *pubkey = algorithm->pubkey; uint8_t digest_ctx[ digest->ctxsize ]; uint8_t digest_out[ digest->digestsize ]; - uint8_t pubkey_ctx[ pubkey->ctxsize ]; int rc; /* Sanity check */ @@ -1148,14 +1148,8 @@ static int x509_check_signature ( struct x509_certificate *cert, } /* Verify signature using signer's public key */ - if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data, - public_key->raw.len ) ) != 0 ) { - DBGC ( cert, "X509 %p \"%s\" cannot initialise public key: " - "%s\n", cert, x509_name ( cert ), strerror ( rc ) ); - goto err_pubkey_init; - } - if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out, - signature->value.data, + if ( ( rc = pubkey_verify ( pubkey, &public_key->raw, digest, + digest_out, signature->value.data, signature->value.len ) ) != 0 ) { DBGC ( cert, "X509 %p \"%s\" signature verification failed: " "%s\n", cert, x509_name ( cert ), strerror ( rc ) ); @@ -1166,8 +1160,6 @@ static int x509_check_signature ( struct x509_certificate *cert, rc = 0; err_pubkey_verify: - pubkey_final ( pubkey, pubkey_ctx ); - err_pubkey_init: err_mismatch: return rc; } @@ -1711,25 +1703,139 @@ void x509_truncate ( struct x509_chain *chain, struct x509_link *link ) { } /** + * Mark X.509 certificate as found + * + * @v store Certificate store + * @v cert X.509 certificate + * @ret cert X.509 certificate + */ +static struct x509_certificate * x509_found ( struct x509_chain *store, + struct x509_certificate *cert ) { + + /* Sanity check */ + assert ( store != NULL ); + + /* Mark as found, if applicable */ + if ( store->found ) + store->found ( store, cert ); + + return cert; +} + +/** + * Identify X.509 certificate by raw certificate data + * + * @v store Certificate store, or NULL to use default + * @v raw Raw certificate data + * @ret cert X.509 certificate, or NULL if not found + */ +struct x509_certificate * x509_find ( struct x509_chain *store, + const struct asn1_cursor *raw ) { + struct x509_link *link; + struct x509_certificate *cert; + + /* Use default certificate store if none specified */ + if ( ! store ) + store = &certstore; + + /* Search for certificate within store */ + list_for_each_entry ( link, &store->links, list ) { + + /* Check raw certificate data */ + cert = link->cert; + if ( asn1_compare ( raw, &cert->raw ) == 0 ) + return x509_found ( store, cert ); + } + + return NULL; +} + +/** * Identify X.509 certificate by subject * - * @v certs X.509 certificate list + * @v store Certificate store, or NULL to use default * @v subject Subject * @ret cert X.509 certificate, or NULL if not found */ -static struct x509_certificate * -x509_find_subject ( struct x509_chain *certs, +struct x509_certificate * +x509_find_subject ( struct x509_chain *store, const struct asn1_cursor *subject ) { struct x509_link *link; struct x509_certificate *cert; + /* Use default certificate store if none specified */ + if ( ! store ) + store = &certstore; + /* Scan through certificate list */ - list_for_each_entry ( link, &certs->links, list ) { + list_for_each_entry ( link, &store->links, list ) { /* Check subject */ cert = link->cert; if ( asn1_compare ( subject, &cert->subject.raw ) == 0 ) - return cert; + return x509_found ( store, cert ); + } + + return NULL; +} + +/** + * Identify X.509 certificate by issuer and serial number + * + * @v store Certificate store, or NULL to use default + * @v issuer Issuer + * @v serial Serial number + * @ret cert X.509 certificate, or NULL if not found + */ +struct x509_certificate * +x509_find_issuer_serial ( struct x509_chain *store, + const struct asn1_cursor *issuer, + const struct asn1_cursor *serial ) { + struct x509_link *link; + struct x509_certificate *cert; + + /* Use default certificate store if none specified */ + if ( ! store ) + store = &certstore; + + /* Scan through certificate list */ + list_for_each_entry ( link, &store->links, list ) { + + /* Check issuer and serial number */ + cert = link->cert; + if ( ( asn1_compare ( issuer, &cert->issuer.raw ) == 0 ) && + ( asn1_compare ( serial, &cert->serial.raw ) == 0 ) ) + return x509_found ( store, cert ); + } + + return NULL; +} + +/** + * Identify X.509 certificate by corresponding public key + * + * @v store Certificate store, or NULL to use default + * @v key Private key + * @ret cert X.509 certificate, or NULL if not found + */ +struct x509_certificate * x509_find_key ( struct x509_chain *store, + struct private_key *key ) { + struct x509_link *link; + struct x509_certificate *cert; + + /* Use default certificate store if none specified */ + if ( ! store ) + store = &certstore; + + /* Scan through certificate list */ + list_for_each_entry ( link, &store->links, list ) { + + /* Check public key */ + cert = link->cert; + if ( pubkey_match ( cert->signature_algorithm->pubkey, + privkey_cursor ( key ), + &cert->subject.public_key.raw ) == 0 ) + return x509_found ( store, cert ); } return NULL; @@ -1739,13 +1845,13 @@ x509_find_subject ( struct x509_chain *certs, * Append X.509 certificates to X.509 certificate chain * * @v chain X.509 certificate chain - * @v certs X.509 certificate list + * @v store Certificate store, or NULL to use default * @ret rc Return status code * * Certificates will be automatically appended to the chain based upon * the subject and issuer names. */ -int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ) { +int x509_auto_append ( struct x509_chain *chain, struct x509_chain *store ) { struct x509_certificate *cert; struct x509_certificate *previous; int rc; @@ -1762,7 +1868,7 @@ int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ) { /* Find issuing certificate */ previous = cert; - cert = x509_find_subject ( certs, &cert->issuer.raw ); + cert = x509_find_subject ( store, &cert->issuer.raw ); if ( ! cert ) break; if ( cert == previous ) @@ -1791,10 +1897,6 @@ int x509_validate_chain ( struct x509_chain *chain, time_t time, struct x509_link *link; int rc; - /* Use default certificate store if none specified */ - if ( ! store ) - store = &certstore; - /* Append any applicable certificates from the certificate store */ if ( ( rc = x509_auto_append ( chain, store ) ) != 0 ) return rc; diff --git a/src/drivers/bus/ecam.c b/src/drivers/bus/ecam.c index 5e3debd..cde5952 100644 --- a/src/drivers/bus/ecam.c +++ b/src/drivers/bus/ecam.c @@ -276,6 +276,7 @@ int ecam_write ( struct pci_device *pci, unsigned int location, return 0; } +PROVIDE_PCIAPI_INLINE ( ecam, pci_can_probe ); PROVIDE_PCIAPI ( ecam, pci_discover, ecam_discover ); PROVIDE_PCIAPI_INLINE ( ecam, pci_read_config_byte ); PROVIDE_PCIAPI_INLINE ( ecam, pci_read_config_word ); diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c index 92b3896..05c9a5c 100644 --- a/src/drivers/bus/pci.c +++ b/src/drivers/bus/pci.c @@ -361,6 +361,10 @@ static int pcibus_probe ( struct root_device *rootdev ) { uint32_t busdevfn = 0; int rc; + /* Skip automatic probing if prohibited */ + if ( ! pci_can_probe() ) + return 0; + do { /* Allocate struct pci_device */ if ( ! pci ) diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c index 7ce5b9e..89483ea 100644 --- a/src/drivers/net/ena.c +++ b/src/drivers/net/ena.c @@ -560,8 +560,11 @@ static int ena_create_cq ( struct ena_nic *ena, struct ena_cq *cq ) { req->create_cq.address = cpu_to_le64 ( virt_to_bus ( cq->cqe.raw ) ); /* Issue request */ - if ( ( rc = ena_admin ( ena, req, &rsp ) ) != 0 ) + if ( ( rc = ena_admin ( ena, req, &rsp ) ) != 0 ) { + DBGC ( ena, "ENA %p CQ%d creation failed (broken firmware?)\n", + ena, cq->id ); goto err_admin; + } /* Parse response */ cq->id = le16_to_cpu ( rsp->create_cq.id ); @@ -1163,7 +1166,7 @@ static int ena_probe ( struct pci_device *pci ) { } ena->info = info; memset ( info, 0, PAGE_SIZE ); - info->type = cpu_to_le32 ( ENA_HOST_INFO_TYPE_LINUX ); + info->type = cpu_to_le32 ( ENA_HOST_INFO_TYPE_IPXE ); snprintf ( info->dist_str, sizeof ( info->dist_str ), "%s", ( product_name[0] ? product_name : product_short_name ) ); snprintf ( info->kernel_str, sizeof ( info->kernel_str ), "%s", diff --git a/src/drivers/net/ena.h b/src/drivers/net/ena.h index 0f280c7..9fda997 100644 --- a/src/drivers/net/ena.h +++ b/src/drivers/net/ena.h @@ -191,14 +191,17 @@ struct ena_host_info { uint32_t features; } __attribute__ (( packed )); -/** Linux operating system type +/** Operating system type * - * There is a defined "iPXE" operating system type (with value 5). - * However, some very broken versions of the ENA firmware will refuse - * to allow a completion queue to be created if the "iPXE" type is - * used. + * Some very broken older versions of the ENA firmware will refuse to + * allow a completion queue to be created if "iPXE" (type 5) is used, + * and require us to pretend that we are "Linux" (type 1) instead. + * + * The ENA team at AWS assures us that the entire AWS fleet has been + * upgraded to fix this bug, and that we are now safe to use the + * correct operating system type value. */ -#define ENA_HOST_INFO_TYPE_LINUX 1 +#define ENA_HOST_INFO_TYPE_IPXE 5 /** Driver version * diff --git a/src/drivers/net/etherfabric.c b/src/drivers/net/etherfabric.c index b40596b..be30b71 100644 --- a/src/drivers/net/etherfabric.c +++ b/src/drivers/net/etherfabric.c @@ -2225,13 +2225,16 @@ falcon_xaui_link_ok ( struct efab_nic *efab ) sync = ( sync == FCN_XX_SYNC_STAT_DECODE_SYNCED ); link_ok = align_done && sync; - } - /* Clear link status ready for next read */ - EFAB_SET_DWORD_FIELD ( reg, FCN_XX_COMMA_DET, FCN_XX_COMMA_DET_RESET ); - EFAB_SET_DWORD_FIELD ( reg, FCN_XX_CHARERR, FCN_XX_CHARERR_RESET); - EFAB_SET_DWORD_FIELD ( reg, FCN_XX_DISPERR, FCN_XX_DISPERR_RESET); - falcon_xmac_writel ( efab, ®, FCN_XX_CORE_STAT_REG_MAC ); + /* Clear link status ready for next read */ + EFAB_SET_DWORD_FIELD ( reg, FCN_XX_COMMA_DET, + FCN_XX_COMMA_DET_RESET ); + EFAB_SET_DWORD_FIELD ( reg, FCN_XX_CHARERR, + FCN_XX_CHARERR_RESET ); + EFAB_SET_DWORD_FIELD ( reg, FCN_XX_DISPERR, + FCN_XX_DISPERR_RESET ); + falcon_xmac_writel ( efab, ®, FCN_XX_CORE_STAT_REG_MAC ); + } has_phyxs = ( efab->phy_op->mmds & ( 1 << MDIO_MMD_PHYXS ) ); if ( link_ok && has_phyxs ) { diff --git a/src/drivers/net/gve.c b/src/drivers/net/gve.c index 7f86dd2..0193e76 100644 --- a/src/drivers/net/gve.c +++ b/src/drivers/net/gve.c @@ -117,10 +117,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); EUNIQ ( EINFO_EIO, ( (status) & 0x1f ), \ EIO_ADMIN_UNSET, EIO_ADMIN_ABORTED, EIO_ADMIN_EXISTS, \ EIO_ADMIN_CANCELLED, EIO_ADMIN_DATALOSS, \ - EIO_ADMIN_DEADLINE, EIO_ADMIN_NOT_FOUND, \ - EIO_ADMIN_RANGE, EIO_ADMIN_PERM, EIO_ADMIN_UNAUTH, \ - EIO_ADMIN_RESOURCE, EIO_ADMIN_UNAVAIL, \ - EIO_ADMIN_NOTSUP, EIO_ADMIN_UNKNOWN ) + EIO_ADMIN_DEADLINE, EIO_ADMIN_PRECONDITION, \ + EIO_ADMIN_INTERNAL, EIO_ADMIN_INVAL, \ + EIO_ADMIN_NOT_FOUND, EIO_ADMIN_RANGE, EIO_ADMIN_PERM, \ + EIO_ADMIN_UNAUTH, EIO_ADMIN_RESOURCE, \ + EIO_ADMIN_UNAVAIL, EIO_ADMIN_NOTSUP, EIO_ADMIN_UNKNOWN ) /****************************************************************************** * diff --git a/src/drivers/net/iphone.c b/src/drivers/net/iphone.c index bbac527..08459a6 100644 --- a/src/drivers/net/iphone.c +++ b/src/drivers/net/iphone.c @@ -362,18 +362,9 @@ static int icert_cert ( struct icert *icert, struct asn1_cursor *subject, struct asn1_builder raw = { NULL, 0 }; uint8_t digest_ctx[SHA256_CTX_SIZE]; uint8_t digest_out[SHA256_DIGEST_SIZE]; - uint8_t pubkey_ctx[RSA_CTX_SIZE]; int len; int rc; - /* Initialise "private" key */ - if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, private->data, - private->len ) ) != 0 ) { - DBGC ( icert, "ICERT %p could not initialise private key: " - "%s\n", icert, strerror ( rc ) ); - goto err_pubkey_init; - } - /* Construct subjectPublicKeyInfo */ if ( ( rc = ( asn1_prepend_raw ( &spki, public->data, public->len ), asn1_prepend_raw ( &spki, icert_nul, @@ -407,14 +398,14 @@ static int icert_cert ( struct icert *icert, struct asn1_cursor *subject, digest_update ( digest, digest_ctx, tbs.data, tbs.len ); digest_final ( digest, digest_ctx, digest_out ); - /* Construct signature */ - if ( ( rc = asn1_grow ( &raw, pubkey_max_len ( pubkey, - pubkey_ctx ) ) ) != 0 ) { + /* Construct signature using "private" key */ + if ( ( rc = asn1_grow ( &raw, + pubkey_max_len ( pubkey, private ) ) ) != 0 ) { DBGC ( icert, "ICERT %p could not build signature: %s\n", icert, strerror ( rc ) ); goto err_grow; } - if ( ( len = pubkey_sign ( pubkey, pubkey_ctx, digest, digest_out, + if ( ( len = pubkey_sign ( pubkey, private, digest, digest_out, raw.data ) ) < 0 ) { rc = len; DBGC ( icert, "ICERT %p could not sign: %s\n", @@ -453,8 +444,6 @@ static int icert_cert ( struct icert *icert, struct asn1_cursor *subject, err_tbs: free ( spki.data ); err_spki: - pubkey_final ( pubkey, pubkey_ctx ); - err_pubkey_init: return rc; } diff --git a/src/drivers/net/marvell/aqc1xx.c b/src/drivers/net/marvell/aqc1xx.c new file mode 100644 index 0000000..b108bf7 --- /dev/null +++ b/src/drivers/net/marvell/aqc1xx.c @@ -0,0 +1,629 @@ +/** @file + * + * Marvell AQtion family network card driver. + * + * Copyright(C) 2017-2024 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +FILE_LICENCE ( BSD2 ); + +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <byteswap.h> +#include <ipxe/netdevice.h> +#include <ipxe/ethernet.h> +#include <ipxe/if_ether.h> +#include <ipxe/iobuf.h> +#include <ipxe/malloc.h> +#include <ipxe/pci.h> +#include <ipxe/profile.h> + +#include "aqc1xx.h" + +extern struct atl_hw_ops atl_hw; +extern struct atl_hw_ops atl2_hw; + +/** @file +* +* Marvell AQC network card driver +* +*/ + +static int atl_ring_alloc ( const struct atl_nic *nic, struct atl_ring *ring, + uint32_t desc_size, uint32_t reg_base ) { + physaddr_t phy_addr; + + /* Allocate ring buffer.*/ + ring->length = ATL_RING_SIZE * desc_size; + ring->ring = dma_alloc ( nic->dma, &ring->map, ring->length, + ring->length ); + + if ( !ring->ring ) + return -ENOMEM; + + /* Initialize the descriptor ring */ + memset ( ring->ring, 0, ring->length ); + + /* Program ring address */ + phy_addr = dma ( &ring->map, ring->ring ); + + /* Write ring address (hi & low parts).*/ + ATL_WRITE_REG ( ( uint32_t )phy_addr, reg_base ); + ATL_WRITE_REG ( ( uint32_t ) ( ( ( uint64_t )phy_addr ) >> 32 ), reg_base + 4 ); + + /* Write ring length.*/ + ATL_WRITE_REG ( ATL_RING_SIZE, reg_base + 8 ); + + ring->sw_head = ring->sw_tail = 0; + + DBGC ( nic, "AQUANTIA: %p ring is at [%08llx,%08llx), reg base %#x\n", + nic, ( ( unsigned long long )phy_addr ), + ( ( unsigned long long ) phy_addr + ring->length ), reg_base ); + + return 0; +} + +static void atl_ring_free ( struct atl_ring *ring ) { + dma_free ( &ring->map, ring->ring, ring->length ); + ring->ring = NULL; + ring->length = 0; +} + +static void atl_ring_next_dx ( unsigned int *val ) { + ++( *val ); + if ( *val == ATL_RING_SIZE ) + *val = 0; +} + +int atl_ring_full ( const struct atl_ring *ring ) { + unsigned int tail = ring->sw_tail; + atl_ring_next_dx ( &tail ); + return tail == ring->sw_head; +} + +void atl_rx_ring_fill ( struct atl_nic *nic ) { + struct atl_desc_rx *rx; + struct io_buffer *iobuf; + physaddr_t address; + unsigned int refilled = 0; + + /* Refill ring */ + while ( !atl_ring_full ( &nic->rx_ring ) ) { + + /* Allocate I/O buffer */ + iobuf = alloc_rx_iob ( ATL_RX_MAX_LEN, nic->dma ); + if ( !iobuf ) { + /* Wait for next refill */ + break; + } + + /* Get next receive descriptor */ + rx = ( struct atl_desc_rx * )nic->rx_ring.ring + + nic->rx_ring.sw_tail; + + /* Populate receive descriptor */ + address = iob_dma ( iobuf ); + rx->data_addr = address; + rx->hdr_addr = 0; + + /* Record I/O buffer */ + assert ( nic->iobufs[nic->rx_ring.sw_tail] == NULL ); + nic->iobufs[nic->rx_ring.sw_tail] = iobuf; + + DBGC( nic, "AQUANTIA: RX[%d] is [%llx,%llx)\n", + nic->rx_ring.sw_tail, + ( ( unsigned long long )address ), + ( ( unsigned long long )address + ATL_RX_MAX_LEN ) ); + + atl_ring_next_dx ( &nic->rx_ring.sw_tail ); + refilled++; + } + + /* Push descriptors to card, if applicable */ + if ( refilled ) { + wmb(); + ATL_WRITE_REG ( nic->rx_ring.sw_tail, ATL_RING_TAIL_PTR ); + } +} + +/** +* Open network device +* +* @v netdev Network device +* @ret rc Return status code +*/ +static int atl_open ( struct net_device *netdev ) { + struct atl_nic *nic = netdev->priv; + uint32_t ctrl = 0; + + /* Tx ring */ + if ( atl_ring_alloc ( nic, &nic->tx_ring, sizeof ( struct atl_desc_tx ), + ATL_TX_DMA_DESC_ADDR ) != 0 ) + goto err_tx_alloc; + + /* Rx ring */ + if ( atl_ring_alloc ( nic, &nic->rx_ring, sizeof ( struct atl_desc_rx ), + ATL_RX_DMA_DESC_ADDR ) != 0 ) + goto err_rx_alloc; + + /* Allocate interrupt vectors */ + ATL_WRITE_REG ( ( ATL_IRQ_CTRL_COR_EN | ATL_IRQ_CTRL_REG_RST_DIS ), + ATL_IRQ_CTRL ); + + /*TX & RX Interruprt Mapping*/ + ctrl = ATL_IRQ_MAP_REG1_RX0 | ATL_IRQ_MAP_REG1_RX0_EN | + ATL_IRQ_MAP_REG1_TX0 | ATL_IRQ_MAP_REG1_TX0_EN; + ATL_WRITE_REG ( ctrl, ATL_IRQ_MAP_REG1 ); + + /*TX interrupt ctrl reg*/ + ATL_WRITE_REG ( ATL_TX_IRQ_CTRL_WB_EN, ATL_TX_IRQ_CTRL ); + + /*RX interrupt ctrl reg*/ + ATL_WRITE_REG ( ATL_RX_IRQ_CTRL_WB_EN, ATL_RX_IRQ_CTRL ); + + /*RX data path*/ + ctrl = ATL_IRQ_TX | ATL_IRQ_RX; + /* itr mask */ + ATL_WRITE_REG ( ctrl, ATL_ITR_MSKS ); + ATL_WRITE_REG ( ( uint32_t )ATL_RX_MAX_LEN / 1024U, + ATL_RX_DMA_DESC_BUF_SIZE ); + + /*filter global ctrl */ + ctrl = ATL_RPF_CTRL1_BRC_EN | ATL_RPF_CTRL1_L2_PROMISC | + ATL_RPF_CTRL1_ACTION | ATL_RPF_CTRL1_BRC_TSH; + ATL_WRITE_REG ( ctrl, ATL_RPF_CTRL1 ); + + /* vlan promisc */ + ATL_WRITE_REG ( ATL_RPF_CTRL2_VLAN_PROMISC, ATL_RPF_CTRL2 ); + /* enable rpf2 */ + ATL_WRITE_REG ( ATL_RPF2_CTRL_EN, ATL_RPF2_CTRL ); + + /* RX Packet Buffer 0 Register 1 */ + ATL_WRITE_REG ( ATL_RPB0_CTRL1_SIZE, ATL_RPB0_CTRL1 ); + + /*RX Packet Buffer 0 Register 2 */ + ctrl = ATL_RPB0_CTRL2_LOW_TSH | ATL_RPB0_CTRL2_HIGH_TSH | + ATL_RPB0_CTRL2_FC_EN; + ATL_WRITE_REG ( ctrl, ATL_RPB0_CTRL2 ); + + /*RPB global ctrl*/ + ctrl = ATL_READ_REG ( ATL_RPB_CTRL ); + ctrl |= ( ATL_RPB_CTRL_EN | ATL_RPB_CTRL_FC ); + ATL_WRITE_REG ( ctrl, ATL_RPB_CTRL ); + + /*TX data path*/ + /* enable tpo2 */ + ATL_WRITE_REG ( ATL_TPO2_EN, ATL_TPO2_CTRL ); + /* tpb global ctrl *** */ + ATL_WRITE_REG ( ATL_TPB0_CTRL1_SIZE, ATL_TPB0_CTRL1 ); + + ctrl = ATL_TPB0_CTRL2_LOW_TSH | ATL_TPB0_CTRL2_HIGH_TSH; + /* tpb global ctrl *** */ + ATL_WRITE_REG ( ctrl, ATL_TPB0_CTRL2 ); + + ctrl = ATL_READ_REG ( ATL_TPB_CTRL ); + ctrl |= ( ATL_TPB_CTRL_EN | ATL_TPB_CTRL_PAD_EN ); + /* tpb global ctrl */ + ATL_WRITE_REG ( ctrl, ATL_TPB_CTRL ); + + /*Enable rings*/ + ATL_WRITE_REG ( ATL_READ_REG ( ATL_RING_TX_CTRL ) | ATL_RING_TX_CTRL_EN, + ATL_RING_TX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG ( ATL_RING_RX_CTRL ) | ATL_RING_RX_CTRL_EN, + ATL_RING_RX_CTRL ); + + if ( nic->flags == ATL_FLAG_A2 ) { + ATL_WRITE_REG ( ATL2_RPF_NEW_EN_ADR_EN, ATL2_RPF_NEW_EN_ADR ); + } + + atl_rx_ring_fill ( nic ); + + nic->hw_ops->start ( nic ); + + return 0; + +err_rx_alloc: + atl_ring_free ( &nic->tx_ring ); + +err_tx_alloc: + return -ENOMEM; +} + +/** +* Close network device +* +* @v netdev Network device +*/ +static void atl_close ( struct net_device *netdev ) { + struct atl_nic *nic = netdev->priv; + + nic->hw_ops->stop ( nic ); + /* rpb global ctrl */ + ATL_WRITE_REG ( ATL_RPB_CTRL_DIS, ATL_RPB_CTRL ); + /* tgb global ctrl */ + ATL_WRITE_REG ( ATL_TPB_CTRL_DIS, ATL_TPB_CTRL); + + ATL_WRITE_REG ( ATL_READ_REG ( ATL_RING_TX_CTRL ) | ( ~ATL_RING_TX_CTRL_EN ), + ATL_RING_TX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG ( ATL_RING_RX_CTRL ) | ( ~ATL_RING_RX_CTRL_EN ), + ATL_RING_RX_CTRL ); + + /* clear itr mask */ + ATL_WRITE_REG ( ATL_ITR_MSKS_DIS, ATL_ITR_MSKS ); + + /* Reset the NIC */ + nic->hw_ops->reset ( nic ); + + atl_ring_free ( &nic->tx_ring ); + atl_ring_free ( &nic->rx_ring ); +} + +/** +* Transmit packet +* +* @v netdev Network device +* @v iobuf I/O buffer +* @ret rc Return status code +*/ +int atl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { + struct atl_nic *nic = netdev->priv; + struct atl_desc_tx *tx; + physaddr_t address; + uint32_t len; + + /* Get next transmit descriptor */ + if ( atl_ring_full ( &nic->tx_ring ) ) { + DBGC ( nic, "AQUANTIA: %p out of transmit descriptors\n", nic ); + return -ENOBUFS; + } + + tx = ( struct atl_desc_tx * )nic->tx_ring.ring + nic->tx_ring.sw_tail; + + /* Populate transmit descriptor */ + memset ( tx, 0, sizeof ( *tx ) ); + address = iob_dma ( iobuf ); + tx->address = address; + len = iob_len ( iobuf ); + + tx->status = 0x1; + tx->status = ( (tx->status) & ~ATL_DESC_TX_BUF_LEN_MASK) | + ( (len << ATL_DESC_TX_BUF_LEN_OFFSET) & + ATL_DESC_TX_BUF_LEN_MASK ); + tx->status = ((tx->status) & ~ATL_DESC_TX_EOP_MASK) | + ( (ATL_DESC_TX_DX_EOP_VALUE << ATL_DESC_TX_EOP_OFFSET) & + ATL_DESC_TX_EOP_MASK ); + tx->status = ( (tx->status) & ~ATL_DESC_TX_CMD_MASK) | + ( (ATL_DESC_TX_CMD_VALUE << ATL_DESC_TX_CMD_OFFSET) & + ATL_DESC_TX_CMD_MASK ); + tx->flag = ( (tx->flag) & ~ATL_DESC_TX_PAY_LEN_MASK) | + ( (len << ATL_DESC_TX_PAY_LEN_OFFSET) & + ATL_DESC_TX_PAY_LEN_MASK ); + wmb(); + + DBGC2 ( nic, "AQUANTIA: %p TX[%d] is [%llx, %llx]\n", + nic, nic->tx_ring.sw_tail, + ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + len ) ); + + atl_ring_next_dx ( &nic->tx_ring.sw_tail ); + ATL_WRITE_REG ( nic->tx_ring.sw_tail, ATL_RING_TAIL ); + + return 0; +} + +void atl_check_link ( struct net_device *netdev ) { + struct atl_nic *nic = netdev->priv; + uint32_t link_state; + + /* Read link status */ + link_state = nic->hw_ops->get_link ( nic ); + + DBGC ( nic, "AQUANTIA: %p link status is %08x\n", nic, link_state ); + + if ( link_state != nic->link_state ) { + if ( link_state ) { + DBGC ( nic, "AQUANTIA: link up\n"); + netdev_link_up ( netdev ); + } else { + DBGC ( nic, "AQUANTIA: link lost\n"); + netdev_link_down ( netdev ); + } + nic->link_state = link_state; + } +} + +/** +* Poll for completed packets +* +* @v netdev Network device +*/ +void atl_poll_tx ( struct net_device *netdev ) { + struct atl_nic *nic = netdev->priv; + struct atl_desc_tx_wb *tx; + + /* Check for completed packets */ + while ( nic->tx_ring.sw_head != nic->tx_ring.sw_tail ) { + + /* Get next transmit descriptor */ + tx = ( struct atl_desc_tx_wb * )nic->tx_ring.ring + + nic->tx_ring.sw_head; + + /* Stop if descriptor is still in use */ + if ( !( tx->status & cpu_to_le32 ( ATL_TX_DESC_STATUS_DD ) ) ) + return; + + DBGC2 ( nic, "AQUANTIA: %p TX[%d] complete\n", + nic, nic->tx_ring.sw_head ); + + /* Complete TX descriptor */ + atl_ring_next_dx ( &nic->tx_ring.sw_head ); + netdev_tx_complete_next ( netdev ); + } +} + +/** +* Poll for received packets +* +* @v netdev Network device +*/ +void atl_poll_rx ( struct net_device *netdev ) { + struct atl_nic *nic = netdev->priv; + struct atl_desc_rx_wb *rx; + struct io_buffer *iobuf; + size_t len; + + /* Check for received packets */ + while ( nic->rx_ring.sw_head != nic->rx_ring.sw_tail ) { + + /* Get next receive descriptor */ + rx = ( struct atl_desc_rx_wb * )nic->rx_ring.ring + + nic->rx_ring.sw_head; + + /* Stop if descriptor is still in use */ + if ( !( rx->status & cpu_to_le16( ATL_RX_DESC_STATUS_DD ) ) ) + return; + + /* Populate I/O buffer */ + iobuf = nic->iobufs[nic->rx_ring.sw_head]; + nic->iobufs[nic->rx_ring.sw_head] = NULL; + len = le16_to_cpu ( rx->pkt_len ); + iob_put ( iobuf, len ); + + /* Hand off to network stack */ + DBGC ( nic, "AQUANTIA: %p RX[%d] complete (length %zd)\n", + nic, nic->rx_ring.sw_head, len ); + + netdev_rx ( netdev, iobuf ); + + atl_ring_next_dx ( &nic->rx_ring.sw_head ); + } +} + +/** +* Poll for completed and received packets +* +* @v netdev Network device +*/ +static void atl_poll ( struct net_device *netdev ) { + struct atl_nic *nic = netdev->priv; + + /* Check link state */ + atl_check_link ( netdev ); + + /* Poll for TX completions */ + atl_poll_tx ( netdev ); + + /* Poll for RX completions */ + atl_poll_rx ( netdev ); + + /* Refill RX ring */ + atl_rx_ring_fill ( nic ); +} + +/** +* Enable or disable interrupts +* +* @v netdev Network device +* @v enable Interrupts should be enabled +*/ +static void atl_irq ( struct net_device *netdev, int enable ) { + struct atl_nic *nic = netdev->priv; + uint32_t mask; + + mask = ( ATL_IRQ_TX | ATL_IRQ_RX ); + if ( enable ) + ATL_WRITE_REG ( mask, ATL_ITR_MSKS ); + else + ATL_WRITE_REG ( mask, ATL_ITR_MSKC ); +} + +/** Marvell network device operations */ +static struct net_device_operations atl_operations = { + .open = atl_open, + .close = atl_close, + .transmit = atl_transmit, + .poll = atl_poll, + .irq = atl_irq, +}; + +/****************************************************************************** +* +* PCI interface +* +******************************************************************************* +*/ + +/** +* Probe PCI device +* +* @v pci PCI device +* @ret rc Return status code +*/ +static int atl_probe ( struct pci_device *pci ) { + struct net_device *netdev; + struct atl_nic *nic; + int rc = ENOERR; + uint32_t io_size = 0; + + /* Allocate and initialise net device */ + netdev = alloc_etherdev ( sizeof( *nic ) ); + if ( !netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &atl_operations ); + nic = netdev->priv; + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset( nic, 0, sizeof ( *nic ) ); + nic->flags = pci->id->driver_data; + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + switch ( nic->flags ) { + case ATL_FLAG_A1: + nic->hw_ops = &atl_hw; + io_size = ATL_BAR_SIZE; + break; + case ATL_FLAG_A2: + nic->hw_ops = &atl2_hw; + io_size = ATL2_BAR_SIZE; + break; + default: + goto err_unsupported; + break; + } + + /* Map registers */ + nic->regs = pci_ioremap ( pci, pci->membase, io_size ); + if ( !nic->regs ) { + rc = -ENODEV; + goto err_ioremap; + } + + /* Configure DMA */ + nic->dma = &pci->dma; + + /* Reset the NIC */ + if ( ( rc = nic->hw_ops->reset ( nic ) ) != 0 ) + goto err_reset; + + /* Get MAC Address */ + if ( ( rc = nic->hw_ops->get_mac ( nic, netdev->hw_addr ) ) != 0 ) + goto err_mac; + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register_netdev; + + /* Set initial link state */ + netdev_link_down ( netdev ); + + return 0; + +err_register_netdev: +err_mac: + nic->hw_ops->reset ( nic ); +err_reset: + iounmap ( nic->regs ); +err_ioremap: + netdev_nullify ( netdev ); + netdev_put ( netdev ); +err_unsupported: +err_alloc: + return rc; +} + +/** +* Remove PCI device +* +* @v pci PCI device +*/ +static void atl_remove ( struct pci_device *pci ) { + struct net_device *netdev = pci_get_drvdata ( pci ); + struct atl_nic *nic = netdev->priv; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Reset the NIC */ + nic->hw_ops->reset ( nic ); + + /* Free network device */ + iounmap ( nic->regs ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** Marvell PCI device IDs */ +static struct pci_device_id atl_nics[] = { + /* Atlantic 1 */ + /* 10G */ + PCI_ROM ( 0x1D6A, 0x0001, "AQC07", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A1 ), + PCI_ROM ( 0x1D6A, 0xD107, "AQC07", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A1 ), + PCI_ROM ( 0x1D6A, 0x07B1, "AQC07", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A1 ), + PCI_ROM ( 0x1D6A, 0x87B1, "AQC07", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A1 ), + + /* SFP */ + PCI_ROM ( 0x1D6A, 0xD100, "AQC00", "Felicity Network Adapter", ATL_FLAG_A1 ), + PCI_ROM ( 0x1D6A, 0x00B1, "AQC00", "Felicity Network Adapter", ATL_FLAG_A1 ), + PCI_ROM ( 0x1D6A, 0x80B1, "AQC00", "Felicity Network Adapter", ATL_FLAG_A1 ), + + /* 5G */ + PCI_ROM ( 0x1D6A, 0xD108, "AQC08", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1 ), + PCI_ROM ( 0x1D6A, 0x08B1, "AQC08", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1 ), + PCI_ROM ( 0x1D6A, 0x88B1, "AQC08", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1 ), + PCI_ROM ( 0x1D6A, 0x11B1, "AQC11", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1 ), + PCI_ROM ( 0x1D6A, 0x91B1, "AQC11", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1 ), + + /* 2.5G */ + PCI_ROM ( 0x1D6A, 0xD109, "AQC09", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1 ), + PCI_ROM ( 0x1D6A, 0x09B1, "AQC09", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1 ), + PCI_ROM ( 0x1D6A, 0x89B1, "AQC09", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1 ), + PCI_ROM ( 0x1D6A, 0x12B1, "AQC12", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1 ), + PCI_ROM ( 0x1D6A, 0x92B1, "AQC12", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1 ), + + /* Atlantic 2 */ + PCI_ROM ( 0x1D6A, 0x00C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2 ), + PCI_ROM ( 0x1D6A, 0x94C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2 ), + PCI_ROM ( 0x1D6A, 0x93C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2 ), + PCI_ROM ( 0x1D6A, 0x04C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2 ), + PCI_ROM ( 0x1D6A, 0x14C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2 ), + PCI_ROM ( 0x1D6A, 0x12C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2 ), + PCI_ROM ( 0x1D6A, 0x03C0, "AQC14", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A2 ), +}; + +/** Marvell PCI driver */ +struct pci_driver atl_driver __pci_driver = { + .ids = atl_nics, + .id_count = ( sizeof( atl_nics ) / sizeof ( atl_nics[0] ) ), + .probe = atl_probe, + .remove = atl_remove, +}; diff --git a/src/drivers/net/marvell/aqc1xx.h b/src/drivers/net/marvell/aqc1xx.h new file mode 100644 index 0000000..26bdd00 --- /dev/null +++ b/src/drivers/net/marvell/aqc1xx.h @@ -0,0 +1,270 @@ +/** @file + * + * Marvell AQtion family network card driver definitions. + * + * Copyright(C) 2017-2024 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _ATLANTIC_H +#define _ATLANTIC_H + +FILE_LICENCE ( BSD2 ); + +#include <stdint.h> +#include <ipxe/if_ether.h> +#include <ipxe/nvs.h> + +#define ATL_BAR_SIZE 0x10000 +#define ATL2_BAR_SIZE 0x40000 +#define ATL_RING_SIZE 64 +#define ATL_RING_ALIGN 128 +#define ATL_RX_MAX_LEN 2048 + +#define ATL_IRQ_TX 0x00000001U +#define ATL_IRQ_RX 0x00000002U + +/*IRQ Status Register*/ +#define ATL_IRQ_STAT_REG 0x00002000U + +/* Interrupt Vector Allocation Register */ +#define ATL_IRQ_CTRL 0x00002300U +#define ATL_IRQ_CTRL_COR_EN 0x00000080U /*IRQ clear on read */ +#define ATL_IRQ_CTRL_REG_RST_DIS 0x20000000U /*Register reset disable */ + +/*TX/RX Interruprt Mapping*/ +#define ATL_IRQ_MAP_REG1 0x00002100U /*IRQ mapping register */ + +#define ATL_IRQ_MAP_REG1_RX0_EN 0x00008000U /*IRQ RX0 enable*/ +#define ATL_IRQ_MAP_REG1_RX0 0x00000100U /*IRQ RX0*/ + +#define ATL_IRQ_MAP_REG1_TX0_EN 0x80000000U /*IRQ TX0 enable*/ +#define ATL_IRQ_MAP_REG1_TX0 0x00000000U /*IRQ TX0*/ + +/*TX interrupt ctrl reg*/ +#define ATL_TX_IRQ_CTRL 0x00007B40U +#define ATL_TX_IRQ_CTRL_WB_EN 0x00000002U + +/*RX interrupt ctrl reg*/ +#define ATL_RX_IRQ_CTRL 0x00005A30U +#define ATL_RX_IRQ_CTRL_WB_EN 0x00000004U + +#define ATL_GLB_CTRL 0x00000000U + +#define ATL_PCI_CTRL 0x00001000U +#define ATL_PCI_CTRL_RST_DIS 0x20000000U + +#define ATL_RX_CTRL 0x00005000U +#define ATL_RX_CTRL_RST_DIS 0x20000000U /*RPB reset disable */ +#define ATL_TX_CTRL 0x00007000U +#define ATL_TX_CTRL_RST_DIS 0x20000000U /*TPB reset disable */ + +/*RX data path control registers*/ +#define ATL_RPF2_CTRL 0x00005040U +#define ATL_RPF2_CTRL_EN 0x000F0000U /* RPF2 enable*/ +#define ATL2_RPF_NEW_EN_ADR_EN 0x00000001U /*enable*/ +#define ATL2_RPF_NEW_EN_ADR 0x5104 + +#define ATL_RPF_CTRL1 0x00005100U +#define ATL_RPF_CTRL1_BRC_EN 0x00000001U /*Allow broadcast receive*/ +#define ATL_RPF_CTRL1_L2_PROMISC 0x00000008U /*L2 promiscious*/ +#define ATL_RPF_CTRL1_ACTION 0x00001000U /*Action to host*/ +#define ATL_RPF_CTRL1_BRC_TSH 0x00010000U /*Brc threshold 256 units per sec*/ + +#define ATL_RPF_CTRL2 0x00005280U +#define ATL_RPF_CTRL2_VLAN_PROMISC 0x00000002U /*VLAN promisc*/ + +#define ATL_RPB_CTRL_DIS 0x0 +#define ATL_RPB_CTRL 0x00005700U +#define ATL_RPB_CTRL_EN 0x00000001U /*RPB Enable*/ +#define ATL_RPB_CTRL_FC 0x00000010U /*RPB Enable*/ +#define ATL_RPB_CTRL_TC_MODE 0x00000100U /*RPB Traffic Class Mode*/ + +#define ATL_RPB0_CTRL1 0x00005710U +#define ATL_RPB0_CTRL1_SIZE 0x00000140U /*RPB size (in unit 1KB) \*/ + +#define ATL_RPB0_CTRL2 0x00005714U + +/*Buffer Low Threshold (70% of RPB size in unit 32B)*/ +#define ATL_RPB0_CTRL2_LOW_TSH 0x00000C00U +/*Buffer High Threshold(30% of RPB size in unit 32B)*/ +#define ATL_RPB0_CTRL2_HIGH_TSH 0x1C000000U +#define ATL_RPB0_CTRL2_FC_EN 0x80000000U /*Flow control Enable*/ + +#define ATL_RX_DMA_DESC_BUF_SIZE 0x00005b18U +#define ATL_RX_DMA_DESC_ADDR 0x00005b00U + +/*TX data path control registers*/ +#define ATL_TPO2_CTRL 0x00007040U +#define ATL_TPO2_EN 0x00010000U /*TPO2 Enable*/ + +#define ATL_TPB_CTRL_DIS 0x0 +#define ATL_TPB_CTRL 0x00007900U +#define ATL_TPB_CTRL_EN 0x00000001U /*TPB enable*/ +#define ATL_TPB_CTRL_PAD_EN 0x00000004U /*Tx pad insert enable*/ +#define ATL_TPB_CTRL_TC_MODE 0x00000100U /*Tx traffic Class Mode*/ + +#define ATL_TPB0_CTRL1 0x00007910U +#define ATL_TPB0_CTRL1_SIZE 0x000000A0U /*TPB Size (in unit 1KB)*/ + +#define ATL_TPB0_CTRL2 0x00007914U +/*Buffer Low Threshold(30% of RPB size in unit 32B)*/ +#define ATL_TPB0_CTRL2_LOW_TSH 0x00000600U +/*Buffer High Threshold(30% of RPB size in unit 32B)*/ +#define ATL_TPB0_CTRL2_HIGH_TSH 0x0E000000U + +#define ATL_TX_DMA_DESC_ADDR 0x00007c00U + +/*Rings control registers*/ +#define ATL_RING_TX_CTRL 0x00007c08U +#define ATL_RING_TX_CTRL_EN 0x80000000U /*Tx descriptor Enable*/ + +#define ATL_RING_RX_CTRL 0x00005b08U +#define ATL_RING_RX_CTRL_EN 0x80000000U /*Rx descriptor Enable*/ + +#define ATL_RING_TAIL 0x00007c10U +#define ATL_RING_TAIL_PTR 0x00005b10U + +/*IRQ control registers*/ +#define ATL_ITR_MSKS_DIS 0x0 +#define ATL_ITR_MSKS 0x00002060U +#define ATL_ITR_MSKS_LSW 0x0000000CU +#define ATL_ITR_MSKC 0x00002070U +#define ATL_ITR_MSKC_LSW 0x0000000CU + +/*Link advertising*/ +#define ATL_LINK_ADV 0x00000368U +#define ATL_SHUT_LINK 0x0 +#define ATL_LINK_ADV_AUTONEG 0xF20U + +#define ATL_LINK_ST 0x00000370U + +/*Semaphores*/ +#define ATL_SEM_RAM 0x000003a8U +#define ATL_SEM_RAM_RESET 0X1 + +/*Mailbox*/ +#define ATL_MBOX_ADDR 0x00000360U +#define ATL_MBOX_CTRL1 0x00000200U +#define ATL_MBOX_CTRL1_START_MBOX_OPT 0x8000 + +#define ATL_MBOX_CTRL3 0x00000208U +#define ATL_MBOX_CTRL5 0x0000020cU + +#define ATL_FLAG_A1 0x1 +#define ATL_FLAG_A2 0x2 + +/*write register*/ +#define ATL_WRITE_REG( VAL, REG ) writel( VAL, nic->regs + (REG) ) +#define ATL_READ_REG( REG ) readl( nic->regs + (REG) ) /*read register*/ + +struct atl_desc_tx { + uint64_t address; + uint32_t status; + uint32_t flag; +} __attribute__ (( packed )); + +#define ATL_DESC_TX_DX_TYPE_VALUE 0x1 + +#define ATL_DESC_TX_DX_EOP_VALUE 0x1 +#define ATL_DESC_TX_EOP_MASK 0x00200000 +#define ATL_DESC_TX_EOP_OFFSET 21 + +#define ATL_DESC_TX_CMD_MASK 0x3FC00000UL +#define ATL_DESC_TX_CMD_OFFSET 22 +#define ATL_DESC_TX_CMD_VALUE 0x22 + +#define ATL_DESC_TX_BUF_LEN_MASK 0x000FFFF0 +#define ATL_DESC_TX_BUF_LEN_OFFSET 5 + +#define ATL_DESC_TX_PAY_LEN_MASK 0xFFFFC000 +#define ATL_DESC_TX_PAY_LEN_OFFSET 14 + +struct atl_desc_tx_wb { + uint64_t rsvd1; + uint32_t status; + uint32_t rsvd4; +} __attribute__ (( packed )); + +#define ATL_TX_DESC_STATUS_DD 0x00100000UL + +struct atl_desc_rx { + uint64_t data_addr; + uint64_t hdr_addr; + +} __attribute__ (( packed )); + +struct atl_desc_rx_wb { + uint64_t rsvd2; + uint16_t status; + uint16_t pkt_len; + uint32_t rsvd4; +} __attribute__ (( packed )); + +#define ATL_RX_DESC_STATUS_DD 0x0001UL +#define ATL_RX_DESC_STATUS_EOP 0x0002UL +struct atl_ring { + unsigned int sw_tail; + unsigned int sw_head; + void *ring; + /** Descriptor ring DMA mapping */ + struct dma_mapping map; + unsigned int length; +}; + +struct atl_nic; + +struct atl_hw_ops { + int ( *reset ) ( struct atl_nic *nic ); + int ( *start ) ( struct atl_nic *nic ); + int ( *stop ) ( struct atl_nic *nic ); + int ( *get_link ) ( struct atl_nic *nic ); + int ( *get_mac ) ( struct atl_nic *, uint8_t *mac ); +}; + +/** An aQuanita network card */ +struct atl_nic { + /** Registers */ + void *regs; + /** Port number (for multi-port devices) */ + unsigned int port; + /** DMA device */ + struct dma_device *dma; + /** Flags */ + unsigned int flags; + struct atl_ring tx_ring; + struct atl_ring rx_ring; + struct io_buffer *iobufs[ATL_RING_SIZE]; + uint32_t link_state; + uint32_t mbox_addr; + struct atl_hw_ops *hw_ops; +}; + +struct atl_hw_stats { + uint32_t version; + uint32_t tid; +}; + +#endif /* _AQUANTIA_H */ diff --git a/src/drivers/net/marvell/atl2_hw.c b/src/drivers/net/marvell/atl2_hw.c new file mode 100644 index 0000000..8058207 --- /dev/null +++ b/src/drivers/net/marvell/atl2_hw.c @@ -0,0 +1,225 @@ +/** @file + * + * Marvell AQtion family network card driver, hardware-specific functions. + * + * Copyright(C) 2017-2024 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +FILE_LICENCE ( BSD2 ); + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <byteswap.h> +#include <ipxe/pci.h> +#include "aqc1xx.h" +#include "atl2_hw.h" + +static int atl2_hw_boot_completed_ ( struct atl_nic *nic ) { + uint32_t reset_status = ATL_READ_REG ( ATL2_GLB_RST_CTRL2 ); + + return ( reset_status & ATL2_RESET_STATUS_BOOT_COMPLETED_MASK ) || + ( ATL_READ_REG ( ATL2_HOST_ITR_REQ ) + & ATL2_FW_HOST_INTERRUPT_REQUEST_READY ); +} + +void atl2_hw_read_shared_in_ ( struct atl_nic *nic, uint32_t offset, + uint32_t *data, uint32_t len ) { + uint32_t i; + + for (i = 0; i < len; ++i ) + { + data[i] = ATL_READ_REG ( ATL2_MIF_SHARED_BUF_IN + offset + i * 4 ); + } +} + +void atl2_hw_write_shared_in_ ( struct atl_nic *nic, uint32_t offset, + uint32_t *data, uint32_t len ) { + uint32_t i; + + for ( i = 0; i < len; ++i ) + { + ATL_WRITE_REG ( data[i], ATL2_MIF_SHARED_BUF_IN + offset + i * 4 ); + } +} + +int atl2_hw_finish_ack_ ( struct atl_nic *nic, uint32_t ms ) { + uint32_t i; + int err = 0; + + ATL_WRITE_REG ( ATL_READ_REG ( ATL2_HOST_FINISHED_WRITE ) + | 1, ATL2_HOST_FINISHED_WRITE ); + + for ( i = 0; i < ( ms / 100 ); ++i ) + { + if ( ( ATL_READ_REG ( ATL2_MCP_BUSY_WRITE ) & 1 ) == 0 ) + { + break; + } + udelay ( ATL2_DELAY_100 ); + } + if (i == ( ms / 100 ) ) + err = -ETIME; + + return err; +} + +int atl2_hw_fw_init_ ( struct atl_nic *nic ) { + uint32_t val; + int err = 0; + + atl2_hw_read_shared_in_ ( nic, ATL2_LINK_CTRL_IN_OFF, &val, 1 ); + val |= ( ATL2_HOST_MODE_ACTIVE | ( 1U << 13 ) ); + atl2_hw_write_shared_in_ ( nic, ATL2_LINK_CTRL_IN_OFF, &val, 1 ); + + atl2_hw_read_shared_in_ ( nic, ATL2_MTU_IN_OFF, &val, 1 ); + val = 16352; + atl2_hw_write_shared_in_ ( nic, ATL2_MTU_IN_OFF, &val, 1 ); + + atl2_hw_read_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + val = 0; + atl2_hw_write_shared_in_( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + err = atl2_hw_finish_ack_ ( nic, 50000000 ); + + return err; +} + +int atl2_hw_reset ( struct atl_nic *nic ) { + int completed = 0; + uint32_t status = 0; + uint32_t request; + int err = 0; + int i; + + request = ATL2_RESET_STATUS_REQ_GSR; + + ATL_WRITE_REG ( request, ATL2_GLB_RST_CTRL2 ); + + /* Wait for boot code started every 10us, 200 ms */ + for ( i = 0; i < 20000; ++i ) + { + status = ATL_READ_REG ( ATL2_GLB_RST_CTRL2 ); + + if ( ( ( status & ATL2_RESET_STATUS_BC_STARTED ) && + ( status != 0xFFFFFFFFu ) ) ) + break; + + udelay ( ATL2_DELAY_10 ); + } + if ( i == 20000 ) + { + DBGC ( nic, "Boot code hanged" ); + err = -EIO; + goto err_exit; + } + + /* Wait for boot succeed, failed or host request every 10us, 480ms */ + for ( i = 0; i < 48000; ++i ) + { + completed = atl2_hw_boot_completed_ ( nic ); + if ( completed ) + break; + + udelay ( ATL2_DELAY_10 ); + } + + if ( !completed ) + { + DBGC ( nic, "FW Restart timed out" ); + err = -ETIME; + goto err_exit; + } + + status = ATL_READ_REG ( ATL2_GLB_RST_CTRL2 ); + + if ( status & ATL2_RESET_STATUS_BOOT_FAILED_MASK ) + { + err = -EIO; + DBGC ( nic, "FW Restart failed" ); + DBGC ( nic, "status = 0x%x", status ); + goto err_exit; + } + + if ( ATL_READ_REG ( ATL2_HOST_ITR_REQ ) + & ATL2_FW_HOST_INTERRUPT_REQUEST_READY ) + { + err = -ENOTSUP; + DBGC ( nic, "Dynamic FW load not implemented" ); + goto err_exit; + } + + err = atl2_hw_fw_init_ ( nic ); + +err_exit: + return err; +} + +int atl2_hw_start ( struct atl_nic *nic ) { + uint32_t val; + + atl2_hw_read_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + val = 0x4B00FFE1; + atl2_hw_write_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + + return atl2_hw_finish_ack_ ( nic, 100000 ); +} + +int atl2_hw_stop ( struct atl_nic *nic ) { + uint32_t val; + + atl2_hw_read_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + val = 0; + atl2_hw_write_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + + return atl2_hw_finish_ack_ ( nic, 100000 ); +} + +int atl2_hw_get_link ( struct atl_nic *nic ) { + uint32_t val; + + val = ATL_READ_REG ( ATL2_MIF_SHARED_BUF_OUT + ATL2_LINK_STS_OUT_OFF ); + + return ( ( val & 0xf ) != 0 ) && ( ( val & 0xF0 ) != 0 ); +} + +int atl2_hw_get_mac ( struct atl_nic *nic, uint8_t *mac ) { + uint32_t mac_addr[2] = {0}; + + atl2_hw_read_shared_in_ ( nic, ATL2_MAC_ADDR_IN_OFF, mac_addr, 2 ); + + memcpy ( mac, ( uint8_t * )mac_addr, 6 ); + + return 0; +} + +struct atl_hw_ops atl2_hw = { + .reset = atl2_hw_reset, + .start = atl2_hw_start, + .stop = atl2_hw_stop, + .get_link = atl2_hw_get_link, + .get_mac = atl2_hw_get_mac, +}; diff --git a/src/drivers/net/marvell/atl2_hw.h b/src/drivers/net/marvell/atl2_hw.h new file mode 100644 index 0000000..d044c21 --- /dev/null +++ b/src/drivers/net/marvell/atl2_hw.h @@ -0,0 +1,94 @@ +/* + * Copyright(C) 2017-2024 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ATL2_HW_H +#define __ATL2_HW_H + +FILE_LICENCE ( BSD2 ); + +#define ATL2_GLB_RST_CTRL2 0x3040 +#define ATL2_HOST_FINISHED_WRITE 0xE00 +#define ATL2_MCP_BUSY_WRITE 0xE04 +#define ATL2_HOST_ITR_REQ 0xF00 + + +#define ATL2_RESET_STATUS_REQ_GSR ( 1U << 0x0 ) +#define ATL2_RESET_STATUS_REQ_HOST_BOOT ( 1U << 0x8 ) +#define ATL2_RESET_STATUS_REQ_MAC_FAST_BOOT ( 1U << 0xA ) +#define ATL2_RESET_STATUS_REQ_PHY_FAST_BOOT ( 1U << 0xB ) + +#define ATL2_RESET_STATUS_HOST_LOAD_COMPLETED ( 1U << 0x10 ) +#define ATL2_RESET_STATUS_REQUIRE_HOST_LOAD ( 1U << 0x11 ) +#define ATL2_RESET_STATUS_BC_STARTED ( 1U << 0x18 ) +#define ATL2_RESET_STATUS_CRASH_DURING_INIT ( 1U << 0x1B ) +#define ATL2_RESET_STATUS_BC_FAILED ( 1U << 0x1C ) +#define ATL2_RESET_STATUS_FW_FAILED ( 1U << 0x1D ) +#define ATL2_RESET_STATUS_FW_SUCCEED ( 1U << 0x1F ) + +#define ATL2_RESET_STATUS_BOOT_FAILED_MASK ( ATL2_RESET_STATUS_CRASH_DURING_INIT | ATL2_RESET_STATUS_BC_FAILED | ATL2_RESET_STATUS_FW_FAILED ) +#define ATL2_RESET_STATUS_BOOT_COMPLETED_MASK ( ATL2_RESET_STATUS_BOOT_FAILED_MASK | ATL2_RESET_STATUS_FW_SUCCEED ) + +#define ATL2_FW_HOST_INTERRUPT_REQUEST_READY 0x0001 +#define ATL2_FW_HOST_INTERRUPT_MAC_READY 0x0004 +#define ATL2_FW_HOST_INTERRUPT_DATA_HANDLED 0x0100 +#define ATL2_FW_HOST_INTERRUPT_LINK_UP 0x0200 +#define ATL2_FW_HOST_INTERRUPT_LINK_DOWN 0x0400 +#define ATL2_FW_HOST_INTERRUPT_PHY_FAULT 0x0800 +#define ATL2_FW_HOST_INTERRUPT_MAC_FAULT 0x1000 +#define ATL2_FW_HOST_INTERRUPT_TEMPERATURE_WARNING 0x2000 +#define ATL2_FW_HOST_INTERRUPT_HEARTBEAT 0x4000 + +#define ATL2_FW_LINK_RATE_INVALID 0 +#define ATL2_FW_LINK_RATE_10M 1 +#define ATL2_FW_LINK_RATE_100M 2 +#define ATL2_FW_LINK_RATE_1G 3 +#define ATL2_FW_LINK_RATE_2G5 4 +#define ATL2_FW_LINK_RATE_5G 5 +#define ATL2_FW_LINK_RATE_10G 6 + +#define ATL2_HOST_MODE_INVALID 0U +#define ATL2_HOST_MODE_ACTIVE 1U +#define ATL2_HOST_MODE_SLEEP_PROXY 2U +#define ATL2_HOST_MODE_LOW_POWER 3U +#define ATL2_HOST_MODE_SHUTDOWN 4U + +#define ATL2_MIF_SHARED_BUF_IN 0x12000 +#define ATL2_MIF_SHARED_BUF_OUT 0x13000 + +#define ATL2_MTU_IN_OFF 0x0 +#define ATL2_MAC_ADDR_IN_OFF 0x8 +#define ATL2_LINK_CTRL_IN_OFF 0x10 +#define ATL2_LINK_OPTS_IN_OFF 0x18 + +#define ATL2_FW_OUT_OFF 0x8 +#define ATL2_LINK_STS_OUT_OFF 0x14 + +#define ATL2_DELAY_10 10 +#define ATL2_DELAY_100 100 + +#endif diff --git a/src/drivers/net/marvell/atl_hw.c b/src/drivers/net/marvell/atl_hw.c new file mode 100644 index 0000000..e0843e6 --- /dev/null +++ b/src/drivers/net/marvell/atl_hw.c @@ -0,0 +1,313 @@ +/** @file + * + * Marvell AQtion family network card driver, hardware-specific functions. + * + * Copyright(C) 2017-2024 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +FILE_LICENCE ( BSD2 ); + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <byteswap.h> +#include <ipxe/pci.h> +#include "aqc1xx.h" +#include "atl_hw.h" +#include <compiler.h> + + +int atl_hw_reset_flb_ ( struct atl_nic *nic ) { + uint32_t val; + int k = 0; + + ATL_WRITE_REG ( ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_STALL, ATL_GLB_CTRL2 ); + mdelay ( ATL_DELAY_50_MNS ); + + /* Cleanup SPI */ + val = ATL_READ_REG ( ATL_GLB_NVR_PROV4 ); + ATL_WRITE_REG ( val | ATL_GBL_NVR_PROV4_RESET, ATL_GLB_NVR_PROV4 ); + + ATL_WRITE_REG( ( ATL_READ_REG ( ATL_GLB_STD_CTRL ) & + ~ATL_GLB_CTRL_RST_DIS ) | ATL_GLB_STD_CTRL_RESET, + ATL_GLB_STD_CTRL ); + + /* Kickstart MAC */ + ATL_WRITE_REG ( ATL_GLB_CTRL2_FW_RESET, ATL_GLB_CTRL2 ); + ATL_WRITE_REG ( ATL_MIF_PWR_GATING_EN_CTRL_RESET, + ATL_MIF_PWR_GATING_EN_CTRL ); + + ATL_WRITE_REG ( ATL_GEN_PROV9_ENABLE, ATL_GEN_PROV9 ); + + /* Reset SPI again because of possible interrupted SPI burst */ + val = ATL_READ_REG ( ATL_GLB_NVR_PROV4 ); + ATL_WRITE_REG ( val | ATL_GBL_NVR_PROV4_RESET, ATL_GLB_NVR_PROV4 ); + mdelay ( ATL_DELAY_10_MNS ); + /* Clear SPI reset state */ + ATL_WRITE_REG ( val & ~ATL_GBL_NVR_PROV4_RESET, ATL_GLB_NVR_PROV4 ); + + /* MAC Kickstart */ + ATL_WRITE_REG ( ATL_GLB_CTRL2_MAC_KICK_START, ATL_GLB_CTRL2 ); + + for (k = 0; k < 1000; k++) { + uint32_t flb_status = ATL_READ_REG ( ATL_MPI_DAISY_CHAIN_STS ); + + flb_status = flb_status & FLB_LOAD_STS; + if ( flb_status ) + break; + mdelay ( ATL_DELAY_10_MNS ); + } + if ( k == 1000 ) { + DBGC (nic, "MAC kickstart failed\n" ); + return -EIO; + } + + /* FW reset */ + ATL_WRITE_REG ( ATL_GLB_CTRL2_FW_RESET, ATL_GLB_CTRL2 ); + mdelay ( ATL_DELAY_50_MNS ); + + ATL_WRITE_REG ( ATL_GBL_MCP_SEM1_RELEASE, ATL_GLB_MCP_SEM1 ); + + /* Global software reset*/ + ATL_WRITE_REG ( ATL_READ_REG ( ATL_RX_CTRL ) & + ~ATL_RX_CTRL_RST_DIS, ATL_RX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG ( ATL_TX_CTRL ) & + ~ATL_TX_CTRL_RST_DIS, ATL_TX_CTRL ); + + ATL_WRITE_REG ( ATL_READ_REG ( ATL_MAC_PHY_CTRL ) & + ~ATL_MAC_PHY_CTRL_RST_DIS, ATL_MAC_PHY_CTRL ); + + ATL_WRITE_REG ( ( ATL_READ_REG ( ATL_GLB_STD_CTRL ) & + ~ATL_GLB_CTRL_RST_DIS ) | ATL_GLB_STD_CTRL_RESET, + ATL_GLB_STD_CTRL ); + + for (k = 0; k < 1000; k++) { + u32 fw_state = ATL_READ_REG ( ATL_FW_VER ); + + if ( fw_state ) + break; + mdelay ( ATL_DELAY_10_MNS ); + } + if ( k == 1000 ) { + DBGC ( nic, "FW kickstart failed\n" ); + return -EIO; + } + /* Old FW requires fixed delay after init */ + mdelay ( ATL_DELAY_15_MNS ); + + return 0; +} + +int atl_hw_reset_rbl_ ( struct atl_nic *nic ) { + uint32_t val, rbl_status; + int k; + + ATL_WRITE_REG ( ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_STALL, ATL_GLB_CTRL2 ); + ATL_WRITE_REG ( ATL_GBL_MCP_SEM1_RELEASE, ATL_GLB_MCP_SEM1 ); + ATL_WRITE_REG ( ATL_MIF_PWR_GATING_EN_CTRL_RESET, + ATL_MIF_PWR_GATING_EN_CTRL ); + + /* Alter RBL status */ + ATL_WRITE_REG ( POISON_SIGN, ATL_MPI_BOOT_EXIT_CODE ); + + /* Cleanup SPI */ + val = ATL_READ_REG ( ATL_GLB_NVR_PROV4 ); + ATL_WRITE_REG ( val | ATL_GBL_NVR_PROV4_RESET, ATL_GLB_NVR_PROV4 ); + + /* Global software reset*/ + ATL_WRITE_REG ( ATL_READ_REG ( ATL_RX_CTRL ) & ~ATL_RX_CTRL_RST_DIS, + ATL_RX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG ( ATL_TX_CTRL ) & ~ATL_TX_CTRL_RST_DIS, + ATL_TX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG ( ATL_MAC_PHY_CTRL ) & + ~ATL_MAC_PHY_CTRL_RST_DIS, ATL_MAC_PHY_CTRL ); + + ATL_WRITE_REG ( ( ATL_READ_REG ( ATL_GLB_STD_CTRL ) & + ~ATL_GLB_CTRL_RST_DIS ) | ATL_GLB_STD_CTRL_RESET, + ATL_GLB_STD_CTRL ); + + ATL_WRITE_REG ( ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_NORMAL, ATL_GLB_CTRL2 ); + + /* Wait for RBL boot */ + for ( k = 0; k < 1000; k++ ) { + rbl_status = ATL_READ_REG ( ATL_MPI_BOOT_EXIT_CODE ) & 0xFFFF; + if ( rbl_status && rbl_status != POISON_SIGN ) + break; + mdelay ( ATL_DELAY_10_MNS ); + } + if ( !rbl_status || rbl_status == POISON_SIGN ) { + DBGC ( nic, "RBL Restart failed\n" ); + return -EIO; + } + + if ( rbl_status == FW_NOT_SUPPORT ) + return -ENOTSUP; + + for ( k = 0; k < 1000; k++ ) { + u32 fw_state = ATL_READ_REG ( ATL_FW_VER ); + + if ( fw_state ) + break; + mdelay ( ATL_DELAY_10_MNS ); + } + if ( k == 1000 ) { + DBGC ( nic, "FW kickstart failed\n" ); + return -EIO; + } + /* Old FW requires fixed delay after init */ + mdelay ( ATL_DELAY_15_MNS ); + + return 0; +} + +int atl_hw_reset ( struct atl_nic *nic ) { + uint32_t boot_exit_code = 0; + uint32_t k; + int rbl_enabled; + uint32_t fw_ver; + uint32_t sem_timeout; + + for ( k = 0; k < 1000; ++k ) { + uint32_t flb_status = ATL_READ_REG ( ATL_MPI_DAISY_CHAIN_STS ); + boot_exit_code = ATL_READ_REG ( ATL_MPI_BOOT_EXIT_CODE ); + if ( flb_status != ATL_MPI_DAISY_CHAIN_STS_ERROR_STATUS || + boot_exit_code != 0 ) + break; + } + + if ( k == 1000 ) { + DBGC ( nic, "Neither RBL nor FLB firmware started\n" ); + return -ENOTSUP; + } + + rbl_enabled = ( boot_exit_code != 0 ); + + fw_ver = ATL_READ_REG ( ATL_FW_VER ); + if ( ( ( fw_ver >> 24 ) & 0xFF ) >= 4 ) { + sem_timeout = ATL_READ_REG ( ATL_SEM_TIMEOUT ); + if ( sem_timeout > ATL_SEM_MAX_TIMEOUT ) + sem_timeout = ATL_SEM_MAX_TIMEOUT; + + for ( k = 0; k < sem_timeout; ++k ) { + if ( ATL_READ_REG ( ATL_GLB_MCP_SEM4 ) ) + break; + + mdelay ( ATL_DELAY_1_MNS ); + } + for ( k = 0; k < sem_timeout; ++k ) { + if ( ATL_READ_REG ( ATL_GLB_MCP_SEM5 ) ) + break; + + mdelay ( ATL_DELAY_1_MNS ); + } + } + + + if ( rbl_enabled ) + return atl_hw_reset_rbl_ ( nic ); + else + return atl_hw_reset_flb_ ( nic ); +} + +int atl_hw_start ( struct atl_nic *nic ) { + ATL_WRITE_REG ( ATL_LINK_ADV_AUTONEG, ATL_LINK_ADV ); + return 0; +} + +int atl_hw_stop ( struct atl_nic *nic ) { + ATL_WRITE_REG ( ATL_SHUT_LINK, ATL_LINK_ADV ); + return 0; +} + +int atl_hw_get_link ( struct atl_nic *nic ) { + return ( ATL_READ_REG ( ATL_LINK_ST) & ATL_LINK_ADV_AUTONEG ) != 0; +} + +int atl_hw_read_mem ( struct atl_nic *nic, uint32_t addr, uint32_t *buffer, + uint32_t size ) { + uint32_t i; + + for ( i = 0; i < 100; ++i ) { + if ( ATL_READ_REG( ATL_SEM_RAM ) ) + break; + mdelay ( ATL_DELAY_1_MNS ); + } + if ( i == 100 ) { + DBGC ( nic, "Semaphore Register not set\n" ); + return -EIO; + } + + ATL_WRITE_REG ( addr, ATL_MBOX_CTRL3 ); + + for ( i = 0; i < size; ++i, addr += 4 ) { + uint32_t j; + + ATL_WRITE_REG ( ATL_MBOX_CTRL1_START_MBOX_OPT, ATL_MBOX_CTRL1 ); + for ( j = 0; j < 10000; ++j ) { + if ( ATL_READ_REG (ATL_MBOX_CTRL3 ) != addr ) + break; + udelay ( ATL_DELAY_10_MNS ); + } + if ( j == 10000 ) { + DBGC ( nic, "Reading from CTRL3 Register Failed\n" ); + return -EIO; + } + + buffer[i] = ATL_READ_REG ( ATL_MBOX_CTRL5 ); + } + + ATL_WRITE_REG( ATL_SEM_RAM_RESET, ATL_SEM_RAM ); + + return 0; +} + +int atl_hw_get_mac ( struct atl_nic *nic, uint8_t *mac ) { + uint32_t mac_addr[2] = {0}; + int err = 0; + uint32_t efuse_addr = ATL_READ_REG ( ATL_GLB_MCP_SP26 ); + + if ( efuse_addr != 0) { + uint32_t mac_efuse_addr = efuse_addr + 40 * sizeof ( uint32_t ); + err = atl_hw_read_mem ( nic, mac_efuse_addr, mac_addr, 2 ); + if ( err != 0 ) + return err; + + mac_addr[0] = cpu_to_be32 ( mac_addr[0] ); + mac_addr[1] = cpu_to_be32 ( mac_addr[1] ); + + memcpy ( mac, ( uint8_t * )mac_addr, ATL_MAC_ADDRESS_SIZE ); + } + return 0; +} + +struct atl_hw_ops atl_hw = { + .reset = atl_hw_reset, + .start = atl_hw_start, + .stop = atl_hw_stop, + .get_link = atl_hw_get_link, + .get_mac = atl_hw_get_mac, +}; diff --git a/src/drivers/net/marvell/atl_hw.h b/src/drivers/net/marvell/atl_hw.h new file mode 100644 index 0000000..efc9f86 --- /dev/null +++ b/src/drivers/net/marvell/atl_hw.h @@ -0,0 +1,83 @@ +/* + * Copyright(C) 2017-2024 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __ATL_HW_H +#define __ATL_HW_H + +FILE_LICENCE ( BSD2 ); + +#define ATL_GLB_STD_CTRL 0x0 +#define ATL_GLB_CTRL_RST_DIS 0x4000 +#define ATL_FW_VER 0x18 + +#define ATL_MPI_DAISY_CHAIN_STS 0x704 +#define ATL_MPI_RX_DAISY_CHAIN_DATA 0x04000000 +#define ATL_MPI_RX_DAISY_CHAIN_SOF 0x02000000 +#define FLB_LOAD_STS 0x10 + +#define ATL_MPI_BOOT_EXIT_CODE 0x388 + +#define ATL_SEM_TIMEOUT 0x348 +#define ATL_SEM_MAX_TIMEOUT 3000 + +#define ATL_GLB_CTRL2 0x404 +#define ATL_GLB_MCP_SEM1 0x3A0 +#define ATL_GBL_MCP_SEM1_RELEASE 0x1 + +#define ATL_GLB_MCP_SEM4 0x3AC +#define ATL_GLB_MCP_SEM5 0x3B0 +#define ATL_GLB_MCP_SP26 0x364 +#define ATL_MIF_PWR_GATING_EN_CTRL 0x32A8 + +#define ATL_GLB_NVR_PROV4 0x53C +#define ATL_GBL_NVR_PROV4_RESET 0x10 + + +#define ATL_GEN_PROV9 0x520 + +#define ATL_MAC_PHY_CTRL 0x00004000U +#define ATL_MAC_PHY_CTRL_RST_DIS 0x20000000U + +#define ATL_MIF_PWR_GATING_EN_CTRL_RESET 0x0 +#define ATL_GEN_PROV9_ENABLE 0x1 +#define ATL_GLB_CTRL2_MAC_KICK_START 0x180e0 +#define ATL_GLB_CTRL2_FW_RESET 0x80e0 +#define ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_STALL 0x40e1 +#define ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_NORMAL 0x40e0 +#define ATL_GLB_STD_CTRL_RESET 0x8000 +#define ATL_MPI_DAISY_CHAIN_STS_ERROR_STATUS 0x06000000 + +#define ATL_DELAY_1_MNS 1 +#define ATL_DELAY_10_MNS 10 +#define ATL_DELAY_15_MNS 15 +#define ATL_DELAY_50_MNS 50 + +#define ATL_MAC_ADDRESS_SIZE 6 +#define POISON_SIGN 0xDEAD +#define FW_NOT_SUPPORT 0xF1A7 + +#endif diff --git a/src/hci/commands/image_crypt_cmd.c b/src/hci/commands/image_crypt_cmd.c new file mode 100644 index 0000000..26e9d79 --- /dev/null +++ b/src/hci/commands/image_crypt_cmd.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2024 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 <stdio.h> +#include <getopt.h> +#include <ipxe/image.h> +#include <ipxe/command.h> +#include <ipxe/parseopt.h> +#include <usr/imgmgmt.h> +#include <usr/imgcrypt.h> + +/** @file + * + * Image encryption management commands + * + */ + +/** "imgdecrypt" options */ +struct imgdecrypt_options { + /** Decrypted image name */ + char *name; + /** Keep envelope after decryption */ + int keep; + /** Download timeout */ + unsigned long timeout; +}; + +/** "imgdecrypt" option list */ +static struct option_descriptor imgdecrypt_opts[] = { + OPTION_DESC ( "name", 'n', required_argument, + struct imgdecrypt_options, name, parse_string ), + OPTION_DESC ( "keep", 'k', no_argument, + struct imgdecrypt_options, keep, parse_flag ), + OPTION_DESC ( "timeout", 't', required_argument, + struct imgdecrypt_options, timeout, parse_timeout), +}; + +/** "imgdecrypt" command descriptor */ +static struct command_descriptor imgdecrypt_cmd = + COMMAND_DESC ( struct imgdecrypt_options, imgdecrypt_opts, 2, 2, + "<uri|image> <envelope uri|image>" ); + +/** + * The "imgdecrypt" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int imgdecrypt_exec ( int argc, char **argv ) { + struct imgdecrypt_options opts; + const char *image_name_uri; + const char *envelope_name_uri; + struct image *image; + struct image *envelope; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &imgdecrypt_cmd, &opts ) ) != 0) + return rc; + + /* Parse image name/URI string */ + image_name_uri = argv[optind]; + + /* Parse envelope name/URI string */ + envelope_name_uri = argv[ optind + 1 ]; + + /* Acquire the image */ + if ( ( rc = imgacquire ( image_name_uri, opts.timeout, &image ) ) != 0 ) + goto err_acquire_image; + + /* Acquire the envelope image */ + if ( ( rc = imgacquire ( envelope_name_uri, opts.timeout, + &envelope ) ) != 0 ) + goto err_acquire_envelope; + + /* Decrypt image */ + if ( ( rc = imgdecrypt ( image, envelope, opts.name ) ) != 0 ) { + printf ( "Could not decrypt: %s\n", strerror ( rc ) ); + goto err_decrypt; + } + + /* Success */ + rc = 0; + + err_decrypt: + /* Discard envelope unless --keep was specified */ + if ( ! opts.keep ) + unregister_image ( envelope ); + err_acquire_envelope: + err_acquire_image: + return rc; +} + +/** Image encryption management commands */ +struct command image_crypt_commands[] __command = { + { + .name = "imgdecrypt", + .exec = imgdecrypt_exec, + }, +}; diff --git a/src/image/der.c b/src/image/der.c index fa17e56..9d31c25 100644 --- a/src/image/der.c +++ b/src/image/der.c @@ -76,8 +76,6 @@ static int der_probe ( struct image *image ) { struct asn1_cursor cursor; uint8_t buf[8]; size_t extra; - size_t total; - int len; int rc; /* Sanity check: no realistic DER image can be smaller than this */ @@ -90,21 +88,16 @@ static int der_probe ( struct image *image ) { copy_from_user ( buf, image->data, 0, sizeof ( buf ) ); extra = ( image->len - sizeof ( buf ) ); - /* Get length of ASN.1 sequence */ - len = asn1_start ( &cursor, ASN1_SEQUENCE, extra ); - if ( len < 0 ) { - rc = len; + /* 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; } - /* Add length of tag and length bytes consumed by asn1_start() */ - total = ( len + ( cursor.data - ( ( void * ) buf ) ) ); - assert ( total <= image->len ); - /* Check that image comprises a single well-formed ASN.1 object */ - if ( total != image->len ) { + if ( extra != ( image->len - sizeof ( buf ) ) ) { DBGC ( image, "DER %s is not single ASN.1\n", image->name ); return -ENOEXEC; } diff --git a/src/include/bits/acpi.h b/src/include/bits/acpi.h new file mode 100644 index 0000000..d984205 --- /dev/null +++ b/src/include/bits/acpi.h @@ -0,0 +1,15 @@ +#ifndef _BITS_ACPI_H +#define _BITS_ACPI_H + +/** @file + * + * Dummy architecture-specific ACPI API implementations + * + * This file is included only if the architecture does not provide its + * own version of this file. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#endif /* _BITS_ACPI_H */ diff --git a/src/arch/loong64/include/gdbmach.h b/src/include/bits/gdbmach.h index cd152ee..7e34985 100644 --- a/src/arch/loong64/include/gdbmach.h +++ b/src/include/bits/gdbmach.h @@ -1,12 +1,12 @@ -#ifndef GDBMACH_H -#define GDBMACH_H +#ifndef _BITS_GDBMACH_H +#define _BITS_GDBMACH_H /** @file * - * GDB architecture specifics + * Dummy GDB architecture specifics * - * This file declares functions for manipulating the machine state and - * debugging context. + * This file is included only if the architecture does not provide its + * own version of this file. * */ @@ -42,4 +42,4 @@ extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable ); extern void gdbmach_init ( void ); -#endif /* GDBMACH_H */ +#endif /* _BITS_GDBMACH_H */ diff --git a/src/include/bits/hyperv.h b/src/include/bits/hyperv.h new file mode 100644 index 0000000..fd7ceee --- /dev/null +++ b/src/include/bits/hyperv.h @@ -0,0 +1,15 @@ +#ifndef _BITS_HYPERV_H +#define _BITS_HYPERV_H + +/** @file + * + * Dummy architecture-specific Hyper-V interface + * + * This file is included only if the architecture does not provide its + * own version of this file. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#endif /* _BITS_HYPERV_H */ diff --git a/src/include/bits/iomap.h b/src/include/bits/iomap.h new file mode 100644 index 0000000..b3d8d0c --- /dev/null +++ b/src/include/bits/iomap.h @@ -0,0 +1,15 @@ +#ifndef _BITS_IOMAP_H +#define _BITS_IOMAP_H + +/** @file + * + * Dummy architecture-specific I/O mapping API implementations + * + * This file is included only if the architecture does not provide its + * own version of this file. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#endif /* _BITS_IOMAP_H */ diff --git a/src/include/bits/mp.h b/src/include/bits/mp.h new file mode 100644 index 0000000..d7d2cdc --- /dev/null +++ b/src/include/bits/mp.h @@ -0,0 +1,15 @@ +#ifndef _BITS_MP_H +#define _BITS_MP_H + +/** @file + * + * Dummy architecture-specific multiprocessor API implementations + * + * This file is included only if the architecture does not provide its + * own version of this file. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#endif /* _BITS_MP_H */ diff --git a/src/include/bits/nap.h b/src/include/bits/nap.h new file mode 100644 index 0000000..7b01f94 --- /dev/null +++ b/src/include/bits/nap.h @@ -0,0 +1,15 @@ +#ifndef _BITS_NAP_H +#define _BITS_NAP_H + +/** @file + * + * Dummy architecture-specific CPU sleeping API implementations + * + * This file is included only if the architecture does not provide its + * own version of this file. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#endif /* _BITS_NAP_H */ diff --git a/src/include/bits/pci_io.h b/src/include/bits/pci_io.h new file mode 100644 index 0000000..711449f --- /dev/null +++ b/src/include/bits/pci_io.h @@ -0,0 +1,15 @@ +#ifndef _BITS_PCI_IO_H +#define _BITS_PCI_IO_H + +/** @file + * + * Dummy architecture-specific PCI I/O API implementations + * + * This file is included only if the architecture does not provide its + * own version of this file. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#endif /* _BITS_PCI_IO_H */ diff --git a/src/include/bits/reboot.h b/src/include/bits/reboot.h new file mode 100644 index 0000000..023647f --- /dev/null +++ b/src/include/bits/reboot.h @@ -0,0 +1,15 @@ +#ifndef _BITS_REBOOT_H +#define _BITS_REBOOT_H + +/** @file + * + * Dummy architecture-specific reboot API implementations + * + * This file is included only if the architecture does not provide its + * own version of this file. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#endif /* _BITS_REBOOT_H */ diff --git a/src/include/bits/sanboot.h b/src/include/bits/sanboot.h new file mode 100644 index 0000000..addbb5b --- /dev/null +++ b/src/include/bits/sanboot.h @@ -0,0 +1,15 @@ +#ifndef _BITS_SANBOOT_H +#define _BITS_SANBOOT_H + +/** @file + * + * Dummy architecture-specific sanboot API implementations + * + * This file is included only if the architecture does not provide its + * own version of this file. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#endif /* _BITS_SANBOOT_H */ diff --git a/src/include/bits/smbios.h b/src/include/bits/smbios.h new file mode 100644 index 0000000..3e06aad --- /dev/null +++ b/src/include/bits/smbios.h @@ -0,0 +1,15 @@ +#ifndef _BITS_SMBIOS_H +#define _BITS_SMBIOS_H + +/** @file + * + * Dummy architecture-specific SMBIOS API implementations + * + * This file is included only if the architecture does not provide its + * own version of this file. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#endif /* _BITS_SMBIOS_H */ diff --git a/src/include/bits/tcpip.h b/src/include/bits/tcpip.h new file mode 100644 index 0000000..9cb54d4 --- /dev/null +++ b/src/include/bits/tcpip.h @@ -0,0 +1,32 @@ +#ifndef _BITS_TCPIP_H +#define _BITS_TCPIP_H + +/** @file + * + * Generic architecture-specific transport-network layer interface + * + * This file is included only if the architecture does not provide its + * own version of this file. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <stdint.h> + +/** + * Calculate continued TCP/IP checkum + * + * @v partial Checksum of already-summed data, in network byte order + * @v data Data buffer + * @v len Length of data buffer + * @ret cksum Updated checksum, in network byte order + */ +static inline __attribute__ (( always_inline )) uint16_t +tcpip_continue_chksum ( uint16_t partial, const void *data, size_t len ) { + + /* Not yet optimised */ + return generic_tcpip_continue_chksum ( partial, data, len ); +} + +#endif /* _BITS_TCPIP_H */ diff --git a/src/include/bits/time.h b/src/include/bits/time.h new file mode 100644 index 0000000..aec9c2f --- /dev/null +++ b/src/include/bits/time.h @@ -0,0 +1,15 @@ +#ifndef _BITS_TIME_H +#define _BITS_TIME_H + +/** @file + * + * Dummy architecture-specific time API implementations + * + * This file is included only if the architecture does not provide its + * own version of this file. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#endif /* _BITS_TIME_H */ diff --git a/src/include/bits/uaccess.h b/src/include/bits/uaccess.h new file mode 100644 index 0000000..09f5f46 --- /dev/null +++ b/src/include/bits/uaccess.h @@ -0,0 +1,15 @@ +#ifndef _BITS_UACCESS_H +#define _BITS_UACCESS_H + +/** @file + * + * Dummy architecture-specific user access API implementations + * + * This file is included only if the architecture does not provide its + * own version of this file. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#endif /* _BITS_UACCESS_H */ diff --git a/src/include/bits/uart.h b/src/include/bits/uart.h new file mode 100644 index 0000000..e132d5c --- /dev/null +++ b/src/include/bits/uart.h @@ -0,0 +1,15 @@ +#ifndef _BITS_UART_H +#define _BITS_UART_H + +/** @file + * + * Dummy architecture-specific UART + * + * This file is included only if the architecture does not provide its + * own version of this file. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#endif /* _BITS_UART_H */ diff --git a/src/include/bits/umalloc.h b/src/include/bits/umalloc.h new file mode 100644 index 0000000..4927f0d --- /dev/null +++ b/src/include/bits/umalloc.h @@ -0,0 +1,15 @@ +#ifndef _BITS_UMALLOC_H +#define _BITS_UMALLOC_H + +/** @file + * + * Dummy architecture-specific user memory allocation API implementations + * + * This file is included only if the architecture does not provide its + * own version of this file. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#endif /* _BITS_UMALLOC_H */ diff --git a/src/arch/loong64/include/bits/xen.h b/src/include/bits/xen.h index 2a3d774..7d0036b 100644 --- a/src/arch/loong64/include/bits/xen.h +++ b/src/include/bits/xen.h @@ -3,7 +3,10 @@ /** @file * - * Xen interface + * Dummy architecture-specific Xen interface + * + * This file is included only if the architecture does not provide its + * own version of this file. * */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index ac7ea56..752b423 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -192,6 +192,48 @@ struct asn1_builder_header { ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 101 ), \ ASN1_OID_SINGLE ( 110 ) +/** ASN.1 OID for id-aes128-cbc (2.16.840.1.101.3.4.1.2) */ +#define ASN1_OID_AES128_CBC \ + ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 101 ), \ + ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 4 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 2 ) + +/** ASN.1 OID for id-aes128-gcm (2.16.840.1.101.3.4.1.6) */ +#define ASN1_OID_AES128_GCM \ + ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 101 ), \ + ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 4 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 6 ) + +/** ASN.1 OID for id-aes192-cbc (2.16.840.1.101.3.4.1.22) */ +#define ASN1_OID_AES192_CBC \ + ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 101 ), \ + ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 4 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 22 ) + +/** ASN.1 OID for id-aes192-gcm (2.16.840.1.101.3.4.1.26) */ +#define ASN1_OID_AES192_GCM \ + ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 101 ), \ + ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 4 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 26 ) + +/** ASN.1 OID for id-aes256-cbc (2.16.840.1.101.3.4.1.42) */ +#define ASN1_OID_AES256_CBC \ + ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 101 ), \ + ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 4 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 42 ) + +/** ASN.1 OID for id-aes256-gcm (2.16.840.1.101.3.4.1.46) */ +#define ASN1_OID_AES256_GCM \ + ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 101 ), \ + ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 4 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 46 ) + /** ASN.1 OID for id-sha256 (2.16.840.1.101.3.4.2.1) */ #define ASN1_OID_SHA256 \ ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \ @@ -261,12 +303,25 @@ struct asn1_builder_header { ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ), \ ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 3 ) -/** ASN.1 OID for pkcs-signedData (1.2.840.113549.1.7.2) */ +/** ASN.1 OID for id-signedData (1.2.840.113549.1.7.2) */ #define ASN1_OID_SIGNEDDATA \ ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \ ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \ ASN1_OID_SINGLE ( 7 ), ASN1_OID_SINGLE ( 2 ) +/** ASN.1 OID for id-envelopedData (1.2.840.113549.1.7.3) */ +#define ASN1_OID_ENVELOPEDDATA \ + ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \ + ASN1_OID_SINGLE ( 7 ), ASN1_OID_SINGLE ( 3 ) + +/** ASN.1 OID for id-authEnvelopedData (1.2.840.113549.1.9.16.1.23) */ +#define ASN1_OID_AUTHENVELOPEDDATA \ + ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \ + ASN1_OID_SINGLE ( 9 ), ASN1_OID_SINGLE ( 16 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 23 ) + /** ASN.1 OID for id-pe-authorityInfoAccess (1.3.6.1.5.5.7.1.1) */ #define ASN1_OID_AUTHORITYINFOACCESS \ ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 6 ), \ @@ -317,8 +372,19 @@ struct asn1_algorithm { struct pubkey_algorithm *pubkey; /** Digest algorithm (if applicable) */ struct digest_algorithm *digest; + /** Cipher algorithm (if applicable) */ + struct cipher_algorithm *cipher; /** Elliptic curve (if applicable) */ struct elliptic_curve *curve; + /** + * Parse algorithm parameters (optional) + * + * @v algorithm Algorithm + * @v param Parameters to parse (and potentially modify) + * @ret rc Return status code + */ + int ( * parse ) ( struct asn1_algorithm *algorithm, + struct asn1_cursor *params ); }; /** ASN.1 OID-identified algorithms */ @@ -404,8 +470,8 @@ asn1_built ( struct asn1_builder *builder ) { return &u->cursor; } -extern int asn1_start ( struct asn1_cursor *cursor, unsigned int type, - size_t extra ); +extern int asn1_enter_partial ( struct asn1_cursor *cursor, unsigned int type, + size_t *extra ); extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ); extern int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ); @@ -423,15 +489,23 @@ extern int asn1_integral_bit_string ( const struct asn1_cursor *cursor, extern int asn1_compare ( const struct asn1_cursor *cursor1, const struct asn1_cursor *cursor2 ); extern int asn1_algorithm ( const struct asn1_cursor *cursor, - struct asn1_algorithm **algorithm ); + struct asn1_algorithm **algorithm, + struct asn1_cursor *params ); extern int asn1_pubkey_algorithm ( const struct asn1_cursor *cursor, struct asn1_algorithm **algorithm ); extern int asn1_digest_algorithm ( const struct asn1_cursor *cursor, struct asn1_algorithm **algorithm ); +extern int asn1_cipher_algorithm ( const struct asn1_cursor *cursor, + struct asn1_algorithm **algorithm, + struct asn1_cursor *params ); extern int asn1_signature_algorithm ( const struct asn1_cursor *cursor, struct asn1_algorithm **algorithm ); extern int asn1_check_algorithm ( const struct asn1_cursor *cursor, struct asn1_algorithm *expected ); +extern int asn1_parse_cbc ( struct asn1_algorithm *algorithm, + struct asn1_cursor *params ); +extern int asn1_parse_gcm ( struct asn1_algorithm *algorithm, + struct asn1_cursor *params ); extern int asn1_generalized_time ( const struct asn1_cursor *cursor, time_t *time ); extern int asn1_grow ( struct asn1_builder *builder, size_t extra ); diff --git a/src/include/ipxe/certstore.h b/src/include/ipxe/certstore.h index ce96666..e276d67 100644 --- a/src/include/ipxe/certstore.h +++ b/src/include/ipxe/certstore.h @@ -9,14 +9,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); -#include <ipxe/asn1.h> #include <ipxe/x509.h> -#include <ipxe/privkey.h> extern struct x509_chain certstore; -extern struct x509_certificate * certstore_find ( struct asn1_cursor *raw ); -extern struct x509_certificate * certstore_find_key ( struct private_key *key ); extern void certstore_add ( struct x509_certificate *cert ); extern void certstore_del ( struct x509_certificate *cert ); diff --git a/src/include/ipxe/cms.h b/src/include/ipxe/cms.h index 7adf724..6d4a78d 100644 --- a/src/include/ipxe/cms.h +++ b/src/include/ipxe/cms.h @@ -16,61 +16,116 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/refcnt.h> #include <ipxe/uaccess.h> -/** CMS signer information */ -struct cms_signer_info { - /** List of signer information blocks */ - struct list_head list; +struct image; +struct cms_message; + +/** A CMS message type */ +struct cms_type { + /** Name */ + const char *name; + /** Object identifier */ + struct asn1_cursor oid; + /** Parse content + * + * @v cms CMS message + * @v raw ASN.1 cursor + * @ret rc Return status code + */ + int ( * parse ) ( struct cms_message *cms, + const struct asn1_cursor *raw ); +}; +/** CMS participant information */ +struct cms_participant { + /** List of participant information blocks */ + struct list_head list; /** Certificate chain */ struct x509_chain *chain; - /** Digest algorithm */ + /** Digest algorithm (for signature messages) */ struct digest_algorithm *digest; /** Public-key algorithm */ struct pubkey_algorithm *pubkey; - /** Signature */ - void *signature; - /** Length of signature */ - size_t signature_len; + /** Signature or key value */ + struct asn1_cursor value; }; -/** A CMS signature */ -struct cms_signature { +/** A CMS message */ +struct cms_message { /** Reference count */ struct refcnt refcnt; - /** List of all certificates */ + /** Raw ASN.1 data */ + struct asn1_cursor *raw; + /** Message type */ + struct cms_type *type; + + /** List of all certificates (for signature messages) */ struct x509_chain *certificates; - /** List of signer information blocks */ - struct list_head info; + /** List of participant information blocks */ + struct list_head participants; + + /** Cipher algorithm */ + struct cipher_algorithm *cipher; + /** Cipher initialization vector */ + struct asn1_cursor iv; + /** Cipher authentication tag */ + struct asn1_cursor mac; }; /** - * Get reference to CMS signature + * Get reference to CMS message * - * @v sig CMS signature - * @ret sig CMS signature + * @v cms CMS message + * @ret cms CMS message */ -static inline __attribute__ (( always_inline )) struct cms_signature * -cms_get ( struct cms_signature *sig ) { - ref_get ( &sig->refcnt ); - return sig; +static inline __attribute__ (( always_inline )) struct cms_message * +cms_get ( struct cms_message *cms ) { + ref_get ( &cms->refcnt ); + return cms; } /** - * Drop reference to CMS signature + * Drop reference to CMS message * - * @v sig CMS signature + * @v cms CMS message */ static inline __attribute__ (( always_inline )) void -cms_put ( struct cms_signature *sig ) { - ref_put ( &sig->refcnt ); +cms_put ( struct cms_message *cms ) { + ref_put ( &cms->refcnt ); +} + +/** + * Check if CMS message is a signature message + * + * @v cms CMS message + * @ret is_signature Message is a signature message + */ +static inline __attribute__ (( always_inline )) int +cms_is_signature ( struct cms_message *cms ) { + + /* CMS signatures include an optional CertificateSet */ + return ( cms->certificates != NULL ); +} + +/** + * Check if CMS message is an encrypted message + * + * @v cms CMS message + * @ret is_encrypted Message is an encrypted message + */ +static inline __attribute__ (( always_inline )) int +cms_is_encrypted ( struct cms_message *cms ) { + + /* CMS encrypted messages have a cipher algorithm */ + return ( cms->cipher != NULL ); } -extern int cms_signature ( const void *data, size_t len, - struct cms_signature **sig ); -extern int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len, +extern int cms_message ( struct image *image, struct cms_message **cms ); +extern int cms_verify ( struct cms_message *cms, struct image *image, const char *name, time_t time, struct x509_chain *store, struct x509_root *root ); +extern int cms_decrypt ( struct cms_message *cms, struct image *image, + const char *name, struct private_key *private_key ); #endif /* _IPXE_CMS_H */ diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index a6f4376..dcc73f3 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdint.h> #include <stddef.h> #include <assert.h> +#include <ipxe/asn1.h> /** A message digest algorithm */ struct digest_algorithm { @@ -120,79 +121,63 @@ struct cipher_algorithm { struct pubkey_algorithm { /** Algorithm name */ const char *name; - /** Context size */ - size_t ctxsize; - /** Initialise algorithm - * - * @v ctx Context - * @v key Key - * @v key_len Length of key - * @ret rc Return status code - */ - int ( * init ) ( void *ctx, const void *key, size_t key_len ); /** Calculate maximum output length * - * @v ctx Context + * @v key Key * @ret max_len Maximum output length */ - size_t ( * max_len ) ( void *ctx ); + size_t ( * max_len ) ( const struct asn1_cursor *key ); /** Encrypt * - * @v ctx Context + * @v key Key * @v plaintext Plaintext * @v plaintext_len Length of plaintext * @v ciphertext Ciphertext * @ret ciphertext_len Length of ciphertext, or negative error */ - int ( * encrypt ) ( void *ctx, const void *data, size_t len, - void *out ); + int ( * encrypt ) ( const struct asn1_cursor *key, const void *data, + size_t len, void *out ); /** Decrypt * - * @v ctx Context + * @v key Key * @v ciphertext Ciphertext * @v ciphertext_len Ciphertext length * @v plaintext Plaintext * @ret plaintext_len Plaintext length, or negative error */ - int ( * decrypt ) ( void *ctx, const void *data, size_t len, - void *out ); + int ( * decrypt ) ( const struct asn1_cursor *key, const void *data, + size_t len, void *out ); /** Sign digest value * - * @v ctx Context + * @v key Key * @v digest Digest algorithm * @v value Digest value * @v signature Signature * @ret signature_len Signature length, or negative error */ - int ( * sign ) ( void *ctx, struct digest_algorithm *digest, - const void *value, void *signature ); + int ( * sign ) ( const struct asn1_cursor *key, + struct digest_algorithm *digest, const void *value, + void *signature ); /** Verify signed digest value * - * @v ctx Context + * @v key Key * @v digest Digest algorithm * @v value Digest value * @v signature Signature * @v signature_len Signature length * @ret rc Return status code */ - int ( * verify ) ( void *ctx, struct digest_algorithm *digest, - const void *value, const void *signature, - size_t signature_len ); - /** Finalise algorithm - * - * @v ctx Context - */ - void ( * final ) ( void *ctx ); + int ( * verify ) ( const struct asn1_cursor *key, + struct digest_algorithm *digest, const void *value, + const void *signature, size_t signature_len ); /** Check that public key matches private key * * @v private_key Private key - * @v private_key_len Private key length * @v public_key Public key - * @v public_key_len Public key length * @ret rc Return status code */ - int ( * match ) ( const void *private_key, size_t private_key_len, - const void *public_key, size_t public_key_len ); + int ( * match ) ( const struct asn1_cursor *private_key, + const struct asn1_cursor *public_key ); }; /** An elliptic curve */ @@ -280,54 +265,43 @@ is_auth_cipher ( struct cipher_algorithm *cipher ) { return cipher->authsize; } -static inline __attribute__ (( always_inline )) int -pubkey_init ( struct pubkey_algorithm *pubkey, void *ctx, - const void *key, size_t key_len ) { - return pubkey->init ( ctx, key, key_len ); -} - static inline __attribute__ (( always_inline )) size_t -pubkey_max_len ( struct pubkey_algorithm *pubkey, void *ctx ) { - return pubkey->max_len ( ctx ); +pubkey_max_len ( struct pubkey_algorithm *pubkey, + const struct asn1_cursor *key ) { + return pubkey->max_len ( key ); } static inline __attribute__ (( always_inline )) int -pubkey_encrypt ( struct pubkey_algorithm *pubkey, void *ctx, +pubkey_encrypt ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key, const void *data, size_t len, void *out ) { - return pubkey->encrypt ( ctx, data, len, out ); + return pubkey->encrypt ( key, data, len, out ); } static inline __attribute__ (( always_inline )) int -pubkey_decrypt ( struct pubkey_algorithm *pubkey, void *ctx, +pubkey_decrypt ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key, const void *data, size_t len, void *out ) { - return pubkey->decrypt ( ctx, data, len, out ); + return pubkey->decrypt ( key, data, len, out ); } static inline __attribute__ (( always_inline )) int -pubkey_sign ( struct pubkey_algorithm *pubkey, void *ctx, +pubkey_sign ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key, struct digest_algorithm *digest, const void *value, void *signature ) { - return pubkey->sign ( ctx, digest, value, signature ); + return pubkey->sign ( key, digest, value, signature ); } static inline __attribute__ (( always_inline )) int -pubkey_verify ( struct pubkey_algorithm *pubkey, void *ctx, +pubkey_verify ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key, struct digest_algorithm *digest, const void *value, const void *signature, size_t signature_len ) { - return pubkey->verify ( ctx, digest, value, signature, signature_len ); -} - -static inline __attribute__ (( always_inline )) void -pubkey_final ( struct pubkey_algorithm *pubkey, void *ctx ) { - pubkey->final ( ctx ); + return pubkey->verify ( key, digest, value, signature, signature_len ); } static inline __attribute__ (( always_inline )) int pubkey_match ( struct pubkey_algorithm *pubkey, - const void *private_key, size_t private_key_len, - const void *public_key, size_t public_key_len ) { - return pubkey->match ( private_key, private_key_len, public_key, - public_key_len ); + const struct asn1_cursor *private_key, + const struct asn1_cursor *public_key ) { + return pubkey->match ( private_key, public_key ); } static inline __attribute__ (( always_inline )) int @@ -348,15 +322,18 @@ extern void cipher_null_decrypt ( void *ctx, const void *src, void *dst, size_t len ); extern void cipher_null_auth ( void *ctx, void *auth ); -extern int pubkey_null_init ( void *ctx, const void *key, size_t key_len ); -extern size_t pubkey_null_max_len ( void *ctx ); -extern int pubkey_null_encrypt ( void *ctx, const void *plaintext, - size_t plaintext_len, void *ciphertext ); -extern int pubkey_null_decrypt ( void *ctx, const void *ciphertext, - size_t ciphertext_len, void *plaintext ); -extern int pubkey_null_sign ( void *ctx, struct digest_algorithm *digest, +extern size_t pubkey_null_max_len ( const struct asn1_cursor *key ); +extern int pubkey_null_encrypt ( const struct asn1_cursor *key, + const void *plaintext, size_t plaintext_len, + void *ciphertext ); +extern int pubkey_null_decrypt ( const struct asn1_cursor *key, + const void *ciphertext, size_t ciphertext_len, + void *plaintext ); +extern int pubkey_null_sign ( const struct asn1_cursor *key, + struct digest_algorithm *digest, const void *value, void *signature ); -extern int pubkey_null_verify ( void *ctx, struct digest_algorithm *digest, +extern int pubkey_null_verify ( const struct asn1_cursor *key, + struct digest_algorithm *digest, const void *value, const void *signature , size_t signature_len ); diff --git a/src/include/ipxe/ecam.h b/src/include/ipxe/ecam.h index ff08aee..f656083 100644 --- a/src/include/ipxe/ecam.h +++ b/src/include/ipxe/ecam.h @@ -54,6 +54,16 @@ struct ecam_mapping { int rc; }; +/** + * Check if PCI bus probing is allowed + * + * @ret ok Bus probing is allowed + */ +static inline __always_inline int +PCIAPI_INLINE ( ecam, pci_can_probe ) ( void ) { + return 1; +} + extern struct pci_api ecam_api; #endif /* _IPXE_ECAM_H */ diff --git a/src/include/ipxe/efi/efi_pci_api.h b/src/include/ipxe/efi/efi_pci_api.h index cf5e1d0..9aca02f 100644 --- a/src/include/ipxe/efi/efi_pci_api.h +++ b/src/include/ipxe/efi/efi_pci_api.h @@ -33,17 +33,13 @@ extern int efipci_write ( struct pci_device *pci, unsigned long location, unsigned long value ); /** - * Find next PCI bus:dev.fn address range in system + * Check if PCI bus probing is allowed * - * @v busdevfn Starting PCI bus:dev.fn address - * @v range PCI bus:dev.fn address range to fill in + * @ret ok Bus probing is allowed */ -static inline __always_inline void -PCIAPI_INLINE ( efi, pci_discover ) ( uint32_t busdevfn __unused, - struct pci_range *range ) { - - /* EFI does not want us to scan the PCI bus ourselves */ - range->count = 0; +static inline __always_inline int +PCIAPI_INLINE ( efi, pci_can_probe ) ( void ) { + return 0; } /** diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 7615075..42bc177 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -225,6 +225,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_pcibridge ( ERRFILE_DRIVER | 0x00d40000 ) #define ERRFILE_mnpnet ( ERRFILE_DRIVER | 0x00d50000 ) #define ERRFILE_gve ( ERRFILE_DRIVER | 0x00d60000 ) +#define ERRFILE_aqc1xx ( ERRFILE_DRIVER | 0x00d70000 ) +#define ERRFILE_atl_hw ( ERRFILE_DRIVER | 0x00d80000 ) +#define ERRFILE_atl2_hw ( ERRFILE_DRIVER | 0x00d90000 ) #define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 ) #define ERRFILE_arp ( ERRFILE_NET | 0x00010000 ) diff --git a/src/include/ipxe/gdbstub.h b/src/include/ipxe/gdbstub.h index 13ca33d..2240cca 100644 --- a/src/include/ipxe/gdbstub.h +++ b/src/include/ipxe/gdbstub.h @@ -11,7 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdint.h> #include <ipxe/tables.h> -#include <gdbmach.h> +#include <bits/gdbmach.h> /** * A transport mechanism for the GDB protocol diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index bfbf236..ca383dc 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -188,6 +188,7 @@ static inline struct image * first_image ( void ) { extern struct image * alloc_image ( struct uri *uri ); extern int image_set_uri ( struct image *image, struct uri *uri ); extern int image_set_name ( struct image *image, const char *name ); +extern char * image_strip_suffix ( struct image *image ); extern int image_set_cmdline ( struct image *image, const char *cmdline ); extern int image_set_len ( struct image *image, size_t len ); extern int image_set_data ( struct image *image, userptr_t data, size_t len ); diff --git a/src/include/ipxe/linux/linux_pci.h b/src/include/ipxe/linux/linux_pci.h index ec6ff8b..2b19e13 100644 --- a/src/include/ipxe/linux/linux_pci.h +++ b/src/include/ipxe/linux/linux_pci.h @@ -23,6 +23,16 @@ extern int linux_pci_write ( struct pci_device *pci, unsigned long where, unsigned long value, size_t len ); /** + * Check if PCI bus probing is allowed + * + * @ret ok Bus probing is allowed + */ +static inline __always_inline int +PCIAPI_INLINE ( linux, pci_can_probe ) ( void ) { + return 1; +} + +/** * Find next PCI bus:dev.fn address range in system * * @v busdevfn Starting PCI bus:dev.fn address diff --git a/src/include/ipxe/pci_io.h b/src/include/ipxe/pci_io.h index 4c035b1..322fdbb 100644 --- a/src/include/ipxe/pci_io.h +++ b/src/include/ipxe/pci_io.h @@ -67,6 +67,13 @@ struct pci_range { #include <bits/pci_io.h> /** + * Check if PCI bus probing is allowed + * + * @ret ok Bus probing is allowed + */ +int pci_can_probe ( void ); + +/** * Find next PCI bus:dev.fn address range in system * * @v busdevfn Starting PCI bus:dev.fn address diff --git a/src/include/ipxe/rsa.h b/src/include/ipxe/rsa.h index a1b5e0c..e36a75e 100644 --- a/src/include/ipxe/rsa.h +++ b/src/include/ipxe/rsa.h @@ -55,31 +55,6 @@ struct rsa_digestinfo_prefix { /** Declare an RSA digestInfo prefix */ #define __rsa_digestinfo_prefix __table_entry ( RSA_DIGESTINFO_PREFIXES, 01 ) -/** An RSA context */ -struct rsa_context { - /** Allocated memory */ - void *dynamic; - /** Modulus */ - bigint_element_t *modulus0; - /** Modulus size */ - unsigned int size; - /** Modulus length */ - size_t max_len; - /** Exponent */ - bigint_element_t *exponent0; - /** Exponent size */ - unsigned int exponent_size; - /** Input buffer */ - bigint_element_t *input0; - /** Output buffer */ - bigint_element_t *output0; - /** Temporary working space for modular exponentiation */ - void *tmp; -}; - -/** RSA context size */ -#define RSA_CTX_SIZE sizeof ( struct rsa_context ) - extern struct pubkey_algorithm rsa_algorithm; #endif /* _IPXE_RSA_H */ diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index cf32778..08d5868 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -240,8 +240,6 @@ struct tls_cipherspec { struct tls_cipher_suite *suite; /** Dynamically-allocated storage */ void *dynamic; - /** Public key encryption context */ - void *pubkey_ctx; /** Bulk encryption cipher context */ void *cipher_ctx; /** MAC secret */ @@ -250,6 +248,14 @@ struct tls_cipherspec { void *fixed_iv; }; +/** A TLS cipher specification pair */ +struct tls_cipherspec_pair { + /** Current cipher specification */ + struct tls_cipherspec active; + /** Next cipher specification */ + struct tls_cipherspec pending; +}; + /** A TLS signature and hash algorithm identifier */ struct tls_signature_hash_id { /** Hash algorithm */ @@ -340,6 +346,70 @@ struct tls_session { struct list_head conn; }; +/** TLS transmit state */ +struct tls_tx { + /** Cipher specifications */ + struct tls_cipherspec_pair cipherspec; + /** Sequence number */ + uint64_t seq; + /** Pending transmissions */ + unsigned int pending; + /** Transmit process */ + struct process process; +}; + +/** TLS receive state */ +struct tls_rx { + /** Cipher specifications */ + struct tls_cipherspec_pair cipherspec; + /** Sequence number */ + uint64_t seq; + /** State machine current state */ + enum tls_rx_state state; + /** Current received record header */ + struct tls_header header; + /** Current received record header (static I/O buffer) */ + struct io_buffer iobuf; + /** List of received data buffers */ + struct list_head data; + /** Received handshake fragment */ + struct io_buffer *handshake; +}; + +/** TLS client state */ +struct tls_client { + /** Random bytes */ + struct tls_client_random random; + /** Private key (if used) */ + struct private_key *key; + /** Certificate chain (if used) */ + struct x509_chain *chain; + /** Security negotiation pending operation */ + struct pending_operation negotiation; +}; + +/** TLS server state */ +struct tls_server { + /** Random bytes */ + uint8_t random[32]; + /** Server Key Exchange record (if any) */ + void *exchange; + /** Server Key Exchange record length */ + size_t exchange_len; + /** Root of trust */ + struct x509_root *root; + /** Certificate chain */ + struct x509_chain *chain; + /** Public key (within server certificate) */ + struct asn1_cursor key; + /** Certificate validator */ + struct interface validator; + /** Certificate validation pending operation */ + struct pending_operation validation; + /** Security negotiation pending operation */ + struct pending_operation negotiation; +}; + /** A TLS connection */ struct tls_connection { /** Reference counter */ @@ -365,70 +435,25 @@ struct tls_connection { /** Protocol version */ uint16_t version; - /** Current TX cipher specification */ - struct tls_cipherspec tx_cipherspec; - /** Next TX cipher specification */ - struct tls_cipherspec tx_cipherspec_pending; - /** Current RX cipher specification */ - struct tls_cipherspec rx_cipherspec; - /** Next RX cipher specification */ - struct tls_cipherspec rx_cipherspec_pending; /** Master secret */ uint8_t master_secret[48]; - /** Server random bytes */ - uint8_t server_random[32]; - /** Client random bytes */ - struct tls_client_random client_random; - /** Server Key Exchange record (if any) */ - void *server_key; - /** Server Key Exchange record length */ - size_t server_key_len; /** Digest algorithm used for handshake verification */ struct digest_algorithm *handshake_digest; /** Digest algorithm context used for handshake verification */ uint8_t *handshake_ctx; - /** Private key */ - struct private_key *key; - /** Client certificate chain (if used) */ - struct x509_chain *certs; /** Secure renegotiation flag */ int secure_renegotiation; /** Verification data */ struct tls_verify_data verify; - /** Root of trust */ - struct x509_root *root; - /** Server certificate chain */ - struct x509_chain *chain; - /** Certificate validator */ - struct interface validator; - - /** Client security negotiation pending operation */ - struct pending_operation client_negotiation; - /** Server security negotiation pending operation */ - struct pending_operation server_negotiation; - /** Certificate validation pending operation */ - struct pending_operation validation; - - /** TX sequence number */ - uint64_t tx_seq; - /** TX pending transmissions */ - unsigned int tx_pending; - /** TX process */ - struct process process; - - /** RX sequence number */ - uint64_t rx_seq; - /** RX state */ - enum tls_rx_state rx_state; - /** Current received record header */ - struct tls_header rx_header; - /** Current received record header (static I/O buffer) */ - struct io_buffer rx_header_iobuf; - /** List of received data buffers */ - struct list_head rx_data; - /** Received handshake fragment */ - struct io_buffer *rx_handshake; + /** Transmit state */ + struct tls_tx tx; + /** Receive state */ + struct tls_rx rx; + /** Client state */ + struct tls_client client; + /** Server state */ + struct tls_server server; }; /** RX I/O buffer size diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index 87323ce..e71cee8 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -17,6 +17,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/list.h> struct image; +struct private_key; /** An X.509 serial number */ struct x509_serial { @@ -201,6 +202,13 @@ struct x509_chain { struct refcnt refcnt; /** List of links */ struct list_head links; + /** Mark certificate as found + * + * @v store Certificate store + * @v cert X.509 certificate + */ + void ( * found ) ( struct x509_chain *store, + struct x509_certificate *cert ); }; /** An X.509 certificate */ @@ -424,8 +432,19 @@ extern int x509_append ( struct x509_chain *chain, extern int x509_append_raw ( struct x509_chain *chain, const void *data, size_t len ); extern void x509_truncate ( struct x509_chain *chain, struct x509_link *link ); +extern struct x509_certificate * x509_find ( struct x509_chain *store, + const struct asn1_cursor *raw ); +extern struct x509_certificate * +x509_find_subject ( struct x509_chain *store, + const struct asn1_cursor *subject ); +extern struct x509_certificate * +x509_find_issuer_serial ( struct x509_chain *store, + const struct asn1_cursor *issuer, + const struct asn1_cursor *serial ); +extern struct x509_certificate * x509_find_key ( struct x509_chain *store, + struct private_key *key ); extern int x509_auto_append ( struct x509_chain *chain, - struct x509_chain *certs ); + struct x509_chain *store ); extern int x509_validate_chain ( struct x509_chain *chain, time_t time, struct x509_chain *store, struct x509_root *root ); diff --git a/src/include/usr/imgcrypt.h b/src/include/usr/imgcrypt.h new file mode 100644 index 0000000..c9408c7 --- /dev/null +++ b/src/include/usr/imgcrypt.h @@ -0,0 +1,17 @@ +#ifndef _USR_IMGCRYPT_H +#define _USR_IMGCRYPT_H + +/** @file + * + * Image encryption management + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <ipxe/image.h> + +extern int imgdecrypt ( struct image *image, struct image *envelope, + const char *name ); + +#endif /* _USR_IMGCRYPT_H */ diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index e2eeeb3..8d4e085 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -63,91 +63,139 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ /** - * Check for a matching PCI root bridge I/O protocol + * Find closest bus:dev.fn address range within a root bridge * - * @v pci PCI device + * @v pci Starting PCI device * @v handle EFI PCI root bridge handle - * @v root EFI PCI root bridge I/O protocol + * @v range PCI bus:dev.fn address range to fill in * @ret rc Return status code */ -static int efipci_root_match ( struct pci_device *pci, EFI_HANDLE handle, - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root ) { +static int efipci_discover_one ( struct pci_device *pci, EFI_HANDLE handle, + struct pci_range *range ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + void *interface; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root; + } root; union { union acpi_resource *res; void *raw; - } u; - unsigned int segment = PCI_SEG ( pci->busdevfn ); - unsigned int bus = PCI_BUS ( pci->busdevfn ); - unsigned int start; - unsigned int end; + } acpi; + uint32_t best = 0; + uint32_t start; + uint32_t count; + uint32_t index; unsigned int tag; EFI_STATUS efirc; int rc; - /* Check segment number */ - if ( root->SegmentNumber != segment ) - return -ENOENT; + /* Return empty range on error */ + range->start = 0; + range->count = 0; + + /* Open root bridge I/O protocol */ + if ( ( efirc = bs->OpenProtocol ( handle, + &efi_pci_root_bridge_io_protocol_guid, + &root.interface, efi_image_handle, handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( pci, "EFIPCI " PCI_FMT " cannot open %s: %s\n", + PCI_ARGS ( pci ), efi_handle_name ( handle ), + strerror ( rc ) ); + goto err_open; + } /* Get ACPI resource descriptors */ - if ( ( efirc = root->Configuration ( root, &u.raw ) ) != 0 ) { + if ( ( efirc = root.root->Configuration ( root.root, + &acpi.raw ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( pci, "EFIPCI " PCI_FMT " cannot get configuration for " "%s: %s\n", PCI_ARGS ( pci ), efi_handle_name ( handle ), strerror ( rc ) ); - return rc; + goto err_config; } - /* Assume success if no bus number range descriptors are found */ - rc = 0; - /* Parse resource descriptors */ - for ( ; ( ( tag = acpi_resource_tag ( u.res ) ) != ACPI_END_RESOURCE ) ; - u.res = acpi_resource_next ( u.res ) ) { + for ( ; ( ( tag = acpi_resource_tag ( acpi.res ) ) != + ACPI_END_RESOURCE ) ; + acpi.res = acpi_resource_next ( acpi.res ) ) { /* Ignore anything other than a bus number range descriptor */ if ( tag != ACPI_QWORD_ADDRESS_SPACE_RESOURCE ) continue; - if ( u.res->qword.type != ACPI_ADDRESS_TYPE_BUS ) + if ( acpi.res->qword.type != ACPI_ADDRESS_TYPE_BUS ) continue; - /* Check for a matching bus number */ - start = le64_to_cpu ( u.res->qword.min ); - end = ( start + le64_to_cpu ( u.res->qword.len ) ); - if ( ( bus >= start ) && ( bus < end ) ) - return 0; + /* Get range for this descriptor */ + start = PCI_BUSDEVFN ( root.root->SegmentNumber, + le64_to_cpu ( acpi.res->qword.min ), + 0, 0 ); + count = PCI_BUSDEVFN ( 0, le64_to_cpu ( acpi.res->qword.len ), + 0, 0 ); + DBGC2 ( pci, "EFIPCI " PCI_FMT " found %04x:[%02x-%02x] via " + "%s\n", PCI_ARGS ( pci ), root.root->SegmentNumber, + PCI_BUS ( start ), PCI_BUS ( start + count - 1 ), + efi_handle_name ( handle ) ); + + /* Check for a matching or new closest range */ + index = ( pci->busdevfn - start ); + if ( ( index < count ) || ( index > best ) ) { + range->start = start; + range->count = count; + best = index; + } - /* We have seen at least one non-matching range - * descriptor, so assume failure unless we find a - * subsequent match. - */ - rc = -ENOENT; + /* Stop if this range contains the target bus:dev.fn address */ + if ( index < count ) + break; + } + + /* If no range descriptors were seen, assume that the root + * bridge has a single bus. + */ + if ( ! range->count ) { + range->start = PCI_BUSDEVFN ( root.root->SegmentNumber, + 0, 0, 0 ); + range->count = PCI_BUSDEVFN ( 0, 1, 0, 0 ); } + /* Success */ + rc = 0; + + err_config: + bs->CloseProtocol ( handle, &efi_pci_root_bridge_io_protocol_guid, + efi_image_handle, handle ); + err_open: return rc; } /** - * Open EFI PCI root bridge I/O protocol + * Find closest bus:dev.fn address range within any root bridge * - * @v pci PCI device - * @ret handle EFI PCI root bridge handle - * @ret root EFI PCI root bridge I/O protocol, or NULL if not found + * @v pci Starting PCI device + * @v range PCI bus:dev.fn address range to fill in + * @v handle PCI root bridge I/O handle to fill in * @ret rc Return status code */ -static int efipci_root_open ( struct pci_device *pci, EFI_HANDLE *handle, - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **root ) { +static int efipci_discover_any ( struct pci_device *pci, + struct pci_range *range, + EFI_HANDLE *handle ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + uint32_t best = 0; + uint32_t index; + struct pci_range tmp; EFI_HANDLE *handles; UINTN num_handles; - union { - void *interface; - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root; - } u; - EFI_STATUS efirc; UINTN i; + EFI_STATUS efirc; int rc; - /* Enumerate all handles */ + /* Return an empty range and no handle on error */ + range->start = 0; + range->count = 0; + *handle = NULL; + + /* Enumerate all root bridge I/O protocol handles */ if ( ( efirc = bs->LocateHandleBuffer ( ByProtocol, &efi_pci_root_bridge_io_protocol_guid, NULL, &num_handles, &handles ) ) != 0 ) { @@ -157,38 +205,102 @@ static int efipci_root_open ( struct pci_device *pci, EFI_HANDLE *handle, goto err_locate; } - /* Look for matching root bridge I/O protocol */ + /* Iterate over all root bridge I/O protocols */ for ( i = 0 ; i < num_handles ; i++ ) { - *handle = handles[i]; - if ( ( efirc = bs->OpenProtocol ( *handle, - &efi_pci_root_bridge_io_protocol_guid, - &u.interface, efi_image_handle, *handle, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( pci, "EFIPCI " PCI_FMT " cannot open %s: %s\n", - PCI_ARGS ( pci ), efi_handle_name ( *handle ), - strerror ( rc ) ); + + /* Get matching or closest range for this root bridge */ + if ( ( rc = efipci_discover_one ( pci, handles[i], + &tmp ) ) != 0 ) continue; + + /* Check for a matching or new closest range */ + index = ( pci->busdevfn - tmp.start ); + if ( ( index < tmp.count ) || ( index > best ) ) { + range->start = tmp.start; + range->count = tmp.count; + best = index; } - if ( efipci_root_match ( pci, *handle, u.root ) == 0 ) { - *root = u.root; - bs->FreePool ( handles ); - return 0; + + /* Stop if this range contains the target bus:dev.fn address */ + if ( index < tmp.count ) { + *handle = handles[i]; + break; } - bs->CloseProtocol ( *handle, - &efi_pci_root_bridge_io_protocol_guid, - efi_image_handle, *handle ); } - DBGC ( pci, "EFIPCI " PCI_FMT " found no root bridge\n", - PCI_ARGS ( pci ) ); - rc = -ENOENT; + /* Check for a range containing the target bus:dev.fn address */ + if ( ! *handle ) { + rc = -ENOENT; + goto err_range; + } + + /* Success */ + rc = 0; + + err_range: bs->FreePool ( handles ); err_locate: return rc; } /** + * Find next PCI bus:dev.fn address range in system + * + * @v busdevfn Starting PCI bus:dev.fn address + * @v range PCI bus:dev.fn address range to fill in + */ +static void efipci_discover ( uint32_t busdevfn, struct pci_range *range ) { + struct pci_device pci; + EFI_HANDLE handle; + + /* Find range */ + memset ( &pci, 0, sizeof ( pci ) ); + pci_init ( &pci, busdevfn ); + efipci_discover_any ( &pci, range, &handle ); +} + +/** + * Open EFI PCI root bridge I/O protocol + * + * @v pci PCI device + * @ret handle EFI PCI root bridge handle + * @ret root EFI PCI root bridge I/O protocol, or NULL if not found + * @ret rc Return status code + */ +static int efipci_root_open ( struct pci_device *pci, EFI_HANDLE *handle, + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **root ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct pci_range tmp; + union { + void *interface; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root; + } u; + EFI_STATUS efirc; + int rc; + + /* Find matching root bridge I/O protocol handle */ + if ( ( rc = efipci_discover_any ( pci, &tmp, handle ) ) != 0 ) + return rc; + + /* (Re)open PCI root bridge I/O protocol */ + if ( ( efirc = bs->OpenProtocol ( *handle, + &efi_pci_root_bridge_io_protocol_guid, + &u.interface, efi_image_handle, *handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( pci, "EFIPCI " PCI_FMT " cannot open %s: %s\n", + PCI_ARGS ( pci ), efi_handle_name ( *handle ), + strerror ( rc ) ); + return rc; + } + + /* Return opened protocol */ + *root = u.root; + + return 0; +} + +/** * Close EFI PCI root bridge I/O protocol * * @v handle EFI PCI root bridge handle @@ -362,7 +474,8 @@ void * efipci_ioremap ( struct pci_device *pci, unsigned long bus_addr, return ioremap ( bus_addr, len ); } -PROVIDE_PCIAPI_INLINE ( efi, pci_discover ); +PROVIDE_PCIAPI_INLINE ( efi, pci_can_probe ); +PROVIDE_PCIAPI ( efi, pci_discover, efipci_discover ); PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte ); PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word ); PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword ); diff --git a/src/interface/linux/linux_pci.c b/src/interface/linux/linux_pci.c index 3008447..a3a0828 100644 --- a/src/interface/linux/linux_pci.c +++ b/src/interface/linux/linux_pci.c @@ -188,6 +188,7 @@ int linux_pci_write ( struct pci_device *pci, unsigned long where, return rc; } +PROVIDE_PCIAPI_INLINE ( linux, pci_can_probe ); PROVIDE_PCIAPI_INLINE ( linux, pci_discover ); PROVIDE_PCIAPI_INLINE ( linux, pci_read_config_byte ); PROVIDE_PCIAPI_INLINE ( linux, pci_read_config_word ); diff --git a/src/net/tls.c b/src/net/tls.c index 5f89be4..ded100d 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -251,8 +251,8 @@ static void tls_set_uint24 ( tls24_t *field24, unsigned long value ) { * @ret is_ready TLS connection is ready */ static int tls_ready ( struct tls_connection *tls ) { - return ( ( ! is_pending ( &tls->client_negotiation ) ) && - ( ! is_pending ( &tls->server_negotiation ) ) ); + return ( ( ! is_pending ( &tls->client.negotiation ) ) && + ( ! is_pending ( &tls->server.negotiation ) ) ); } /** @@ -382,21 +382,21 @@ static void free_tls ( struct refcnt *refcnt ) { /* Free dynamically-allocated resources */ free ( tls->new_session_ticket ); - tls_clear_cipher ( tls, &tls->tx_cipherspec ); - tls_clear_cipher ( tls, &tls->tx_cipherspec_pending ); - tls_clear_cipher ( tls, &tls->rx_cipherspec ); - tls_clear_cipher ( tls, &tls->rx_cipherspec_pending ); - free ( tls->server_key ); + tls_clear_cipher ( tls, &tls->tx.cipherspec.active ); + tls_clear_cipher ( tls, &tls->tx.cipherspec.pending ); + tls_clear_cipher ( tls, &tls->rx.cipherspec.active ); + tls_clear_cipher ( tls, &tls->rx.cipherspec.pending ); + free ( tls->server.exchange ); free ( tls->handshake_ctx ); - list_for_each_entry_safe ( iobuf, tmp, &tls->rx_data, list ) { + list_for_each_entry_safe ( iobuf, tmp, &tls->rx.data, list ) { list_del ( &iobuf->list ); free_iob ( iobuf ); } - free_iob ( tls->rx_handshake ); - x509_chain_put ( tls->certs ); - x509_chain_put ( tls->chain ); - x509_root_put ( tls->root ); - privkey_put ( tls->key ); + free_iob ( tls->rx.handshake ); + privkey_put ( tls->client.key ); + x509_chain_put ( tls->client.chain ); + x509_chain_put ( tls->server.chain ); + x509_root_put ( tls->server.root ); /* Drop reference to session */ assert ( list_empty ( &tls->list ) ); @@ -415,17 +415,17 @@ static void free_tls ( struct refcnt *refcnt ) { static void tls_close ( struct tls_connection *tls, int rc ) { /* Remove pending operations, if applicable */ - pending_put ( &tls->client_negotiation ); - pending_put ( &tls->server_negotiation ); - pending_put ( &tls->validation ); + pending_put ( &tls->client.negotiation ); + pending_put ( &tls->server.negotiation ); + pending_put ( &tls->server.validation ); /* Remove process */ - process_del ( &tls->process ); + process_del ( &tls->tx.process ); /* Close all interfaces */ intf_shutdown ( &tls->cipherstream, rc ); intf_shutdown ( &tls->plainstream, rc ); - intf_shutdown ( &tls->validator, rc ); + intf_shutdown ( &tls->server.validator, rc ); /* Remove from session */ list_del ( &tls->list ); @@ -640,15 +640,15 @@ static void tls_generate_master_secret ( struct tls_connection *tls, DBGC ( tls, "TLS %p pre-master-secret:\n", tls ); DBGC_HD ( tls, pre_master_secret, pre_master_secret_len ); DBGC ( tls, "TLS %p client random bytes:\n", tls ); - DBGC_HD ( tls, &tls->client_random, sizeof ( tls->client_random ) ); + DBGC_HD ( tls, &tls->client.random, sizeof ( tls->client.random ) ); DBGC ( tls, "TLS %p server random bytes:\n", tls ); - DBGC_HD ( tls, &tls->server_random, sizeof ( tls->server_random ) ); + DBGC_HD ( tls, &tls->server.random, sizeof ( tls->server.random ) ); tls_prf_label ( tls, pre_master_secret, pre_master_secret_len, &tls->master_secret, sizeof ( tls->master_secret ), "master secret", - &tls->client_random, sizeof ( tls->client_random ), - &tls->server_random, sizeof ( tls->server_random ) ); + &tls->client.random, sizeof ( tls->client.random ), + &tls->server.random, sizeof ( tls->server.random ) ); DBGC ( tls, "TLS %p generated master secret:\n", tls ); DBGC_HD ( tls, &tls->master_secret, sizeof ( tls->master_secret ) ); @@ -662,8 +662,8 @@ static void tls_generate_master_secret ( struct tls_connection *tls, * The master secret must already be known. */ static int tls_generate_keys ( struct tls_connection *tls ) { - struct tls_cipherspec *tx_cipherspec = &tls->tx_cipherspec_pending; - struct tls_cipherspec *rx_cipherspec = &tls->rx_cipherspec_pending; + struct tls_cipherspec *tx_cipherspec = &tls->tx.cipherspec.pending; + struct tls_cipherspec *rx_cipherspec = &tls->rx.cipherspec.pending; size_t hash_size = tx_cipherspec->suite->mac_len; size_t key_size = tx_cipherspec->suite->key_len; size_t iv_size = tx_cipherspec->suite->fixed_iv_len; @@ -675,8 +675,8 @@ static int tls_generate_keys ( struct tls_connection *tls ) { /* Generate key block */ tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ), key_block, sizeof ( key_block ), "key expansion", - &tls->server_random, sizeof ( tls->server_random ), - &tls->client_random, sizeof ( tls->client_random ) ); + &tls->server.random, sizeof ( tls->server.random ), + &tls->client.random, sizeof ( tls->client.random ) ); /* Split key block into portions */ key = key_block; @@ -856,10 +856,6 @@ tls_find_cipher_suite ( unsigned int cipher_suite ) { static void tls_clear_cipher ( struct tls_connection *tls __unused, struct tls_cipherspec *cipherspec ) { - if ( cipherspec->suite ) { - pubkey_final ( cipherspec->suite->pubkey, - cipherspec->pubkey_ctx ); - } free ( cipherspec->dynamic ); memset ( cipherspec, 0, sizeof ( *cipherspec ) ); cipherspec->suite = &tls_cipher_suite_null; @@ -876,7 +872,6 @@ static void tls_clear_cipher ( struct tls_connection *tls __unused, static int tls_set_cipher ( struct tls_connection *tls, struct tls_cipherspec *cipherspec, struct tls_cipher_suite *suite ) { - struct pubkey_algorithm *pubkey = suite->pubkey; struct cipher_algorithm *cipher = suite->cipher; size_t total; void *dynamic; @@ -885,8 +880,7 @@ static int tls_set_cipher ( struct tls_connection *tls, tls_clear_cipher ( tls, cipherspec ); /* Allocate dynamic storage */ - total = ( pubkey->ctxsize + cipher->ctxsize + suite->mac_len + - suite->fixed_iv_len ); + total = ( cipher->ctxsize + suite->mac_len + suite->fixed_iv_len ); dynamic = zalloc ( total ); if ( ! dynamic ) { DBGC ( tls, "TLS %p could not allocate %zd bytes for crypto " @@ -896,7 +890,6 @@ static int tls_set_cipher ( struct tls_connection *tls, /* Assign storage */ cipherspec->dynamic = dynamic; - cipherspec->pubkey_ctx = dynamic; dynamic += pubkey->ctxsize; cipherspec->cipher_ctx = dynamic; dynamic += cipher->ctxsize; cipherspec->mac_secret = dynamic; dynamic += suite->mac_len; cipherspec->fixed_iv = dynamic; dynamic += suite->fixed_iv_len; @@ -936,10 +929,10 @@ static int tls_select_cipher ( struct tls_connection *tls, return rc; /* Set ciphers */ - if ( ( rc = tls_set_cipher ( tls, &tls->tx_cipherspec_pending, + if ( ( rc = tls_set_cipher ( tls, &tls->tx.cipherspec.pending, suite ) ) != 0 ) return rc; - if ( ( rc = tls_set_cipher ( tls, &tls->rx_cipherspec_pending, + if ( ( rc = tls_set_cipher ( tls, &tls->rx.cipherspec.pending, suite ) ) != 0 ) return rc; @@ -955,22 +948,20 @@ static int tls_select_cipher ( struct tls_connection *tls, * Activate next cipher suite * * @v tls TLS connection - * @v pending Pending cipher specification - * @v active Active cipher specification to replace + * @v pair Cipher specification pair * @ret rc Return status code */ static int tls_change_cipher ( struct tls_connection *tls, - struct tls_cipherspec *pending, - struct tls_cipherspec *active ) { + struct tls_cipherspec_pair *pair ) { /* Sanity check */ - if ( pending->suite == &tls_cipher_suite_null ) { + if ( pair->pending.suite == &tls_cipher_suite_null ) { DBGC ( tls, "TLS %p refusing to use null cipher\n", tls ); return -ENOTSUP_NULL; } - tls_clear_cipher ( tls, active ); - memswap ( active, pending, sizeof ( *active ) ); + tls_clear_cipher ( tls, &pair->active ); + memswap ( &pair->active, &pair->pending, sizeof ( pair->active ) ); return 0; } @@ -1088,7 +1079,7 @@ tls_find_named_curve ( unsigned int named_curve ) { * @v tls TLS connection */ static void tls_tx_resume ( struct tls_connection *tls ) { - process_add ( &tls->process ); + process_add ( &tls->tx.process ); } /** @@ -1111,16 +1102,16 @@ static void tls_tx_resume_all ( struct tls_session *session ) { static void tls_restart ( struct tls_connection *tls ) { /* Sanity check */ - assert ( ! tls->tx_pending ); - assert ( ! is_pending ( &tls->client_negotiation ) ); - assert ( ! is_pending ( &tls->server_negotiation ) ); - assert ( ! is_pending ( &tls->validation ) ); + assert ( ! tls->tx.pending ); + assert ( ! is_pending ( &tls->client.negotiation ) ); + assert ( ! is_pending ( &tls->server.negotiation ) ); + assert ( ! is_pending ( &tls->server.validation ) ); /* (Re)start negotiation */ - tls->tx_pending = TLS_TX_CLIENT_HELLO; + tls->tx.pending = TLS_TX_CLIENT_HELLO; tls_tx_resume ( tls ); - pending_get ( &tls->client_negotiation ); - pending_get ( &tls->server_negotiation ); + pending_get ( &tls->client.negotiation ); + pending_get ( &tls->server.negotiation ); } /** @@ -1239,7 +1230,7 @@ static int tls_client_hello ( struct tls_connection *tls, htonl ( sizeof ( hello ) - sizeof ( hello.type_length ) ) ); hello.version = htons ( TLS_VERSION_MAX ); - memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) ); + memcpy ( &hello.random, &tls->client.random, sizeof ( hello.random ) ); hello.session_id_len = tls->session_id_len; memcpy ( hello.session_id, tls->session_id, sizeof ( hello.session_id ) ); @@ -1346,7 +1337,7 @@ static int tls_send_certificate ( struct tls_connection *tls ) { /* Calculate length of client certificates */ len = 0; - list_for_each_entry ( link, &tls->certs->links, list ) { + list_for_each_entry ( link, &tls->client.chain->links, list ) { cert = link->cert; len += ( sizeof ( *certificate ) + cert->raw.len ); DBGC ( tls, "TLS %p sending client certificate %s\n", @@ -1367,7 +1358,7 @@ static int tls_send_certificate ( struct tls_connection *tls ) { sizeof ( certificates->type_length ) ) ); tls_set_uint24 ( &certificates->length, len ); certificate = &certificates->certificates[0]; - list_for_each_entry ( link, &tls->certs->links, list ) { + list_for_each_entry ( link, &tls->client.chain->links, list ) { cert = link->cert; tls_set_uint24 ( &certificate->length, cert->raw.len ); memcpy ( certificate->data, cert->raw.data, cert->raw.len ); @@ -1392,9 +1383,9 @@ static int tls_send_certificate ( struct tls_connection *tls ) { * @ret rc Return status code */ static int tls_send_client_key_exchange_pubkey ( struct tls_connection *tls ) { - struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending; + struct tls_cipherspec *cipherspec = &tls->tx.cipherspec.pending; struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey; - size_t max_len = pubkey_max_len ( pubkey, cipherspec->pubkey_ctx ); + size_t max_len = pubkey_max_len ( pubkey, &tls->server.key ); struct { uint16_t version; uint8_t random[46]; @@ -1421,8 +1412,8 @@ static int tls_send_client_key_exchange_pubkey ( struct tls_connection *tls ) { /* Encrypt pre-master secret using server's public key */ memset ( &key_xchg, 0, sizeof ( key_xchg ) ); - len = pubkey_encrypt ( pubkey, cipherspec->pubkey_ctx, - &pre_master_secret, sizeof ( pre_master_secret ), + len = pubkey_encrypt ( pubkey, &tls->server.key, &pre_master_secret, + sizeof ( pre_master_secret ), key_xchg.encrypted_pre_master_secret ); if ( len < 0 ) { rc = len; @@ -1458,7 +1449,7 @@ struct tls_key_exchange_algorithm tls_pubkey_exchange_algorithm = { */ static int tls_verify_dh_params ( struct tls_connection *tls, size_t param_len ) { - struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending; + struct tls_cipherspec *cipherspec = &tls->tx.cipherspec.pending; struct pubkey_algorithm *pubkey; struct digest_algorithm *digest; int use_sig_hash = tls_version ( tls, TLS_VERSION_TLS_1_2 ); @@ -1472,9 +1463,9 @@ static int tls_verify_dh_params ( struct tls_connection *tls, int rc; /* Signature follows parameters */ - assert ( param_len <= tls->server_key_len ); - data = ( tls->server_key + param_len ); - remaining = ( tls->server_key_len - param_len ); + assert ( param_len <= tls->server.exchange_len ); + data = ( tls->server.exchange + param_len ); + remaining = ( tls->server.exchange_len - param_len ); /* Parse signature from ServerKeyExchange */ sig = data; @@ -1483,7 +1474,8 @@ static int tls_verify_dh_params ( struct tls_connection *tls, sizeof ( *sig ) ) ) ) { DBGC ( tls, "TLS %p received underlength ServerKeyExchange\n", tls ); - DBGC_HDA ( tls, 0, tls->server_key, tls->server_key_len ); + DBGC_HDA ( tls, 0, tls->server.exchange, + tls->server.exchange_len ); return -EINVAL_KEY_EXCHANGE; } @@ -1516,21 +1508,21 @@ static int tls_verify_dh_params ( struct tls_connection *tls, /* Calculate digest */ digest_init ( digest, ctx ); - digest_update ( digest, ctx, &tls->client_random, - sizeof ( tls->client_random ) ); - digest_update ( digest, ctx, tls->server_random, - sizeof ( tls->server_random ) ); - digest_update ( digest, ctx, tls->server_key, param_len ); + digest_update ( digest, ctx, &tls->client.random, + sizeof ( tls->client.random ) ); + digest_update ( digest, ctx, tls->server.random, + sizeof ( tls->server.random ) ); + digest_update ( digest, ctx, tls->server.exchange, param_len ); digest_final ( digest, ctx, hash ); /* Verify signature */ - if ( ( rc = pubkey_verify ( pubkey, cipherspec->pubkey_ctx, + if ( ( rc = pubkey_verify ( pubkey, &tls->server.key, digest, hash, signature, signature_len ) ) != 0 ) { DBGC ( tls, "TLS %p ServerKeyExchange failed " "verification\n", tls ); - DBGC_HDA ( tls, 0, tls->server_key, - tls->server_key_len ); + DBGC_HDA ( tls, 0, tls->server.exchange, + tls->server.exchange_len ); return -EPERM_KEY_EXCHANGE; } } @@ -1545,7 +1537,7 @@ static int tls_verify_dh_params ( struct tls_connection *tls, * @ret rc Return status code */ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { - uint8_t private[ sizeof ( tls->client_random.random ) ]; + uint8_t private[ sizeof ( tls->client.random.random ) ]; const struct { uint16_t len; uint8_t data[0]; @@ -1558,8 +1550,8 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { int rc; /* Parse ServerKeyExchange */ - data = tls->server_key; - remaining = tls->server_key_len; + data = tls->server.exchange; + remaining = tls->server.exchange_len; for ( i = 0 ; i < ( sizeof ( dh_val ) / sizeof ( dh_val[0] ) ) ; i++ ){ dh_val[i] = data; if ( ( sizeof ( *dh_val[i] ) > remaining ) || @@ -1567,8 +1559,8 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { sizeof ( *dh_val[i] ) ) )){ DBGC ( tls, "TLS %p received underlength " "ServerKeyExchange\n", tls ); - DBGC_HDA ( tls, 0, tls->server_key, - tls->server_key_len ); + DBGC_HDA ( tls, 0, tls->server.exchange, + tls->server.exchange_len ); rc = -EINVAL_KEY_EXCHANGE; goto err_header; } @@ -1576,7 +1568,7 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { data += frag_len; remaining -= frag_len; } - param_len = ( tls->server_key_len - remaining ); + param_len = ( tls->server.exchange_len - remaining ); /* Verify parameter signature */ if ( ( rc = tls_verify_dh_params ( tls, param_len ) ) != 0 ) @@ -1681,12 +1673,14 @@ static int tls_send_client_key_exchange_ecdhe ( struct tls_connection *tls ) { int rc; /* Parse ServerKeyExchange record */ - ecdh = tls->server_key; - if ( ( sizeof ( *ecdh ) > tls->server_key_len ) || - ( ecdh->public_len > ( tls->server_key_len - sizeof ( *ecdh ) ))){ + ecdh = tls->server.exchange; + if ( ( sizeof ( *ecdh ) > tls->server.exchange_len ) || + ( ecdh->public_len > ( tls->server.exchange_len - + sizeof ( *ecdh ) ) ) ) { DBGC ( tls, "TLS %p received underlength ServerKeyExchange\n", tls ); - DBGC_HDA ( tls, 0, tls->server_key, tls->server_key_len ); + DBGC_HDA ( tls, 0, tls->server.exchange, + tls->server.exchange_len ); return -EINVAL_KEY_EXCHANGE; } param_len = ( sizeof ( *ecdh ) + ecdh->public_len ); @@ -1699,14 +1693,16 @@ static int tls_send_client_key_exchange_ecdhe ( struct tls_connection *tls ) { if ( ecdh->curve_type != TLS_NAMED_CURVE_TYPE ) { DBGC ( tls, "TLS %p unsupported curve type %d\n", tls, ecdh->curve_type ); - DBGC_HDA ( tls, 0, tls->server_key, tls->server_key_len ); + DBGC_HDA ( tls, 0, tls->server.exchange, + tls->server.exchange_len ); return -ENOTSUP_CURVE; } curve = tls_find_named_curve ( ecdh->named_curve ); if ( ! curve ) { DBGC ( tls, "TLS %p unsupported named curve %d\n", tls, ntohs ( ecdh->named_curve ) ); - DBGC_HDA ( tls, 0, tls->server_key, tls->server_key_len ); + DBGC_HDA ( tls, 0, tls->server.exchange, + tls->server.exchange_len ); return -ENOTSUP_CURVE; } @@ -1714,7 +1710,8 @@ static int tls_send_client_key_exchange_ecdhe ( struct tls_connection *tls ) { if ( ecdh->public_len != curve->curve->keysize ) { DBGC ( tls, "TLS %p invalid %s key\n", tls, curve->curve->name ); - DBGC_HDA ( tls, 0, tls->server_key, tls->server_key_len ); + DBGC_HDA ( tls, 0, tls->server.exchange, + tls->server.exchange_len ); return -EINVAL_KEY_EXCHANGE; } @@ -1783,7 +1780,7 @@ struct tls_key_exchange_algorithm tls_ecdhe_exchange_algorithm = { * @ret rc Return status code */ static int tls_send_client_key_exchange ( struct tls_connection *tls ) { - struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending; + struct tls_cipherspec *cipherspec = &tls->tx.cipherspec.pending; struct tls_cipher_suite *suite = cipherspec->suite; int rc; @@ -1812,24 +1809,16 @@ static int tls_send_client_key_exchange ( struct tls_connection *tls ) { */ static int tls_send_certificate_verify ( struct tls_connection *tls ) { struct digest_algorithm *digest = tls->handshake_digest; - struct x509_certificate *cert = x509_first ( tls->certs ); + struct x509_certificate *cert = x509_first ( tls->client.chain ); struct pubkey_algorithm *pubkey = cert->signature_algorithm->pubkey; - struct asn1_cursor *key = privkey_cursor ( tls->key ); + struct asn1_cursor *key = privkey_cursor ( tls->client.key ); uint8_t digest_out[ digest->digestsize ]; - uint8_t ctx[ pubkey->ctxsize ]; struct tls_signature_hash_algorithm *sig_hash = NULL; int rc; /* Generate digest to be signed */ tls_verify_handshake ( tls, digest_out ); - /* Initialise public-key algorithm */ - if ( ( rc = pubkey_init ( pubkey, ctx, key->data, key->len ) ) != 0 ) { - DBGC ( tls, "TLS %p could not initialise %s client private " - "key: %s\n", tls, pubkey->name, strerror ( rc ) ); - goto err_pubkey_init; - } - /* TLSv1.2 and later use explicit algorithm identifiers */ if ( tls_version ( tls, TLS_VERSION_TLS_1_2 ) ) { sig_hash = tls_signature_hash_algorithm ( pubkey, digest ); @@ -1844,7 +1833,7 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) { /* Generate and transmit record */ { - size_t max_len = pubkey_max_len ( pubkey, ctx ); + size_t max_len = pubkey_max_len ( pubkey, key ); int use_sig_hash = ( ( sig_hash == NULL ) ? 0 : 1 ); struct { uint32_t type_length; @@ -1856,7 +1845,7 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) { int len; /* Sign digest */ - len = pubkey_sign ( pubkey, ctx, digest, digest_out, + len = pubkey_sign ( pubkey, key, digest, digest_out, certificate_verify.signature ); if ( len < 0 ) { rc = len; @@ -1889,8 +1878,6 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) { err_pubkey_sign: err_sig_hash: - pubkey_final ( pubkey, ctx ); - err_pubkey_init: return rc; } @@ -1946,7 +1933,7 @@ static int tls_send_finished ( struct tls_connection *tls ) { return rc; /* Mark client as finished */ - pending_put ( &tls->client_negotiation ); + pending_put ( &tls->client.negotiation ); return 0; } @@ -1976,13 +1963,12 @@ static int tls_new_change_cipher ( struct tls_connection *tls, iob_pull ( iobuf, sizeof ( *change_cipher ) ); /* Change receive cipher spec */ - if ( ( rc = tls_change_cipher ( tls, &tls->rx_cipherspec_pending, - &tls->rx_cipherspec ) ) != 0 ) { + if ( ( rc = tls_change_cipher ( tls, &tls->rx.cipherspec ) ) != 0 ) { DBGC ( tls, "TLS %p could not activate RX cipher: %s\n", tls, strerror ( rc ) ); return rc; } - tls->rx_seq = ~( ( uint64_t ) 0 ); + tls->rx.seq = ~( ( uint64_t ) 0 ); return 0; } @@ -2188,8 +2174,8 @@ static int tls_new_server_hello ( struct tls_connection *tls, return rc; /* Copy out server random bytes */ - memcpy ( &tls->server_random, &hello_a->random, - sizeof ( tls->server_random ) ); + memcpy ( &tls->server.random, &hello_a->random, + sizeof ( tls->server.random ) ); /* Check session ID */ if ( hello_a->session_id_len && @@ -2309,12 +2295,13 @@ static int tls_parse_chain ( struct tls_connection *tls, int rc; /* Free any existing certificate chain */ - x509_chain_put ( tls->chain ); - tls->chain = NULL; + memset ( &tls->server.key, 0, sizeof ( tls->server.key ) ); + x509_chain_put ( tls->server.chain ); + tls->server.chain = NULL; /* Create certificate chain */ - tls->chain = x509_alloc_chain(); - if ( ! tls->chain ) { + tls->server.chain = x509_alloc_chain(); + if ( ! tls->server.chain ) { rc = -ENOMEM_CHAIN; goto err_alloc_chain; } @@ -2346,14 +2333,15 @@ static int tls_parse_chain ( struct tls_connection *tls, record_len = ( sizeof ( *certificate ) + certificate_len ); /* Add certificate to chain */ - if ( ( rc = x509_append_raw ( tls->chain, certificate->data, + if ( ( rc = x509_append_raw ( tls->server.chain, + certificate->data, certificate_len ) ) != 0 ) { DBGC ( tls, "TLS %p could not append certificate: %s\n", tls, strerror ( rc ) ); DBGC_HDA ( tls, 0, data, remaining ); goto err_parse; } - cert = x509_last ( tls->chain ); + cert = x509_last ( tls->server.chain ); DBGC ( tls, "TLS %p found certificate %s\n", tls, x509_name ( cert ) ); @@ -2367,8 +2355,9 @@ static int tls_parse_chain ( struct tls_connection *tls, err_parse: err_overlength: err_underlength: - x509_chain_put ( tls->chain ); - tls->chain = NULL; + memset ( &tls->server.key, 0, sizeof ( tls->server.key ) ); + x509_chain_put ( tls->server.chain ); + tls->server.chain = NULL; err_alloc_chain: return rc; } @@ -2425,12 +2414,12 @@ static int tls_new_server_key_exchange ( struct tls_connection *tls, const void *data, size_t len ) { /* Free any existing server key exchange record */ - free ( tls->server_key ); - tls->server_key_len = 0; + free ( tls->server.exchange ); + tls->server.exchange_len = 0; /* Allocate copy of server key exchange record */ - tls->server_key = malloc ( len ); - if ( ! tls->server_key ) + tls->server.exchange = malloc ( len ); + if ( ! tls->server.exchange ) return -ENOMEM; /* Store copy of server key exchange record for later @@ -2438,8 +2427,8 @@ static int tls_new_server_key_exchange ( struct tls_connection *tls, * since the certificate validation will not yet have * completed. */ - memcpy ( tls->server_key, data, len ); - tls->server_key_len = len; + memcpy ( tls->server.exchange, data, len ); + tls->server.exchange_len = len; return 0; } @@ -2463,11 +2452,11 @@ static int tls_new_certificate_request ( struct tls_connection *tls, */ /* Free any existing client certificate chain */ - x509_chain_put ( tls->certs ); - tls->certs = NULL; + x509_chain_put ( tls->client.chain ); + tls->client.chain = NULL; /* Determine client certificate to be sent */ - cert = certstore_find_key ( tls->key ); + cert = x509_find_key ( NULL, tls->client.key ); if ( ! cert ) { DBGC ( tls, "TLS %p could not find certificate corresponding " "to private key\n", tls ); @@ -2479,18 +2468,18 @@ static int tls_new_certificate_request ( struct tls_connection *tls, tls, x509_name ( cert ) ); /* Create client certificate chain */ - tls->certs = x509_alloc_chain(); - if ( ! tls->certs ) { + tls->client.chain = x509_alloc_chain(); + if ( ! tls->client.chain ) { rc = -ENOMEM; goto err_alloc; } /* Append client certificate to chain */ - if ( ( rc = x509_append ( tls->certs, cert ) ) != 0 ) + if ( ( rc = x509_append ( tls->client.chain, cert ) ) != 0 ) goto err_append; /* Append any relevant issuer certificates */ - if ( ( rc = x509_auto_append ( tls->certs, &certstore ) ) != 0 ) + if ( ( rc = x509_auto_append ( tls->client.chain, &certstore ) ) != 0 ) goto err_auto_append; /* Drop local reference to client certificate */ @@ -2500,8 +2489,8 @@ static int tls_new_certificate_request ( struct tls_connection *tls, err_auto_append: err_append: - x509_chain_put ( tls->certs ); - tls->certs = NULL; + x509_chain_put ( tls->client.chain ); + tls->client.chain = NULL; err_alloc: x509_put ( cert ); err_find: @@ -2532,13 +2521,14 @@ static int tls_new_server_hello_done ( struct tls_connection *tls, } /* Begin certificate validation */ - if ( ( rc = create_validator ( &tls->validator, tls->chain, - tls->root ) ) != 0 ) { + if ( ( rc = create_validator ( &tls->server.validator, + tls->server.chain, + tls->server.root ) ) != 0 ) { DBGC ( tls, "TLS %p could not start certificate validation: " "%s\n", tls, strerror ( rc ) ); return rc; } - pending_get ( &tls->validation ); + pending_get ( &tls->server.validation ); return 0; } @@ -2580,14 +2570,14 @@ static int tls_new_finished ( struct tls_connection *tls, } /* Mark server as finished */ - pending_put ( &tls->server_negotiation ); + pending_put ( &tls->server.negotiation ); /* If we are resuming a session (i.e. if the server Finished * arrives before the client Finished is sent), then schedule * transmission of Change Cipher and Finished. */ - if ( is_pending ( &tls->client_negotiation ) ) { - tls->tx_pending |= ( TLS_TX_CHANGE_CIPHER | TLS_TX_FINISHED ); + if ( is_pending ( &tls->client.negotiation ) ) { + tls->tx.pending |= ( TLS_TX_CHANGE_CIPHER | TLS_TX_FINISHED ); tls_tx_resume ( tls ); } @@ -2788,7 +2778,7 @@ static int tls_new_record ( struct tls_connection *tls, unsigned int type, break; case TLS_TYPE_HANDSHAKE: handler = tls_new_handshake; - iobuf = &tls->rx_handshake; + iobuf = &tls->rx.handshake; break; default: DBGC ( tls, "TLS %p unknown record type %d\n", tls, type ); @@ -2935,7 +2925,7 @@ static void tls_hmac_list ( struct tls_cipherspec *cipherspec, */ static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type, const void *data, size_t len ) { - struct tls_cipherspec *cipherspec = &tls->tx_cipherspec; + struct tls_cipherspec *cipherspec = &tls->tx.cipherspec.active; struct tls_cipher_suite *suite = cipherspec->suite; struct cipher_algorithm *cipher = suite->cipher; struct digest_algorithm *digest = suite->digest; @@ -2962,7 +2952,7 @@ static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type, } /* Construct authentication data */ - authhdr.seq = cpu_to_be64 ( tls->tx_seq ); + authhdr.seq = cpu_to_be64 ( tls->tx.seq ); authhdr.header.type = type; authhdr.header.version = htons ( tls->version ); authhdr.header.length = htons ( len ); @@ -3046,7 +3036,7 @@ static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type, } /* Update TX state machine to next record */ - tls->tx_seq += 1; + tls->tx.seq += 1; assert ( plaintext == NULL ); assert ( ciphertext == NULL ); @@ -3107,7 +3097,7 @@ static int tls_verify_padding ( struct tls_connection *tls, static int tls_new_ciphertext ( struct tls_connection *tls, struct tls_header *tlshdr, struct list_head *rx_data ) { - struct tls_cipherspec *cipherspec = &tls->rx_cipherspec; + struct tls_cipherspec *cipherspec = &tls->rx.cipherspec.active; struct tls_cipher_suite *suite = cipherspec->suite; struct cipher_algorithm *cipher = suite->cipher; struct digest_algorithm *digest = suite->digest; @@ -3156,7 +3146,7 @@ static int tls_new_ciphertext ( struct tls_connection *tls, auth = last->tail; /* Construct authentication data */ - authhdr.seq = cpu_to_be64 ( tls->rx_seq ); + authhdr.seq = cpu_to_be64 ( tls->rx.seq ); authhdr.header.type = tlshdr->type; authhdr.header.version = tlshdr->version; authhdr.header.length = htons ( len ); @@ -3172,7 +3162,7 @@ static int tls_new_ciphertext ( struct tls_connection *tls, /* Decrypt the received data */ check_len = 0; - list_for_each_entry ( iobuf, &tls->rx_data, list ) { + list_for_each_entry ( iobuf, &tls->rx.data, list ) { cipher_decrypt ( cipher, cipherspec->cipher_ctx, iobuf->data, iobuf->data, iob_len ( iobuf ) ); check_len += iob_len ( iobuf ); @@ -3298,8 +3288,8 @@ static int tls_progress ( struct tls_connection *tls, struct job_progress *progress ) { /* Return cipherstream or validator progress as applicable */ - if ( is_pending ( &tls->validation ) ) { - return job_progress ( &tls->validator, progress ); + if ( is_pending ( &tls->server.validation ) ) { + return job_progress ( &tls->server.validator, progress ); } else { return job_progress ( &tls->cipherstream, progress ); } @@ -3334,10 +3324,10 @@ static struct interface_descriptor tls_plainstream_desc = * @ret rc Returned status code */ static int tls_newdata_process_header ( struct tls_connection *tls ) { - struct tls_cipherspec *cipherspec = &tls->rx_cipherspec; + struct tls_cipherspec *cipherspec = &tls->rx.cipherspec.active; struct cipher_algorithm *cipher = cipherspec->suite->cipher; size_t iv_len = cipherspec->suite->record_iv_len; - size_t data_len = ntohs ( tls->rx_header.length ); + size_t data_len = ntohs ( tls->rx.header.length ); size_t remaining = data_len; size_t frag_len; size_t reserve; @@ -3353,7 +3343,7 @@ static int tls_newdata_process_header ( struct tls_connection *tls ) { remaining += reserve; /* Allocate data buffers now that we know the length */ - assert ( list_empty ( &tls->rx_data ) ); + assert ( list_empty ( &tls->rx.data ) ); while ( remaining ) { /* Calculate fragment length. Ensure that no block is @@ -3394,16 +3384,16 @@ static int tls_newdata_process_header ( struct tls_connection *tls ) { reserve = 0; /* Add I/O buffer to list */ - list_add_tail ( &iobuf->list, &tls->rx_data ); + list_add_tail ( &iobuf->list, &tls->rx.data ); } /* Move to data state */ - tls->rx_state = TLS_RX_DATA; + tls->rx.state = TLS_RX_DATA; return 0; err: - list_for_each_entry_safe ( iobuf, tmp, &tls->rx_data, list ) { + list_for_each_entry_safe ( iobuf, tmp, &tls->rx.data, list ) { list_del ( &iobuf->list ); free_iob ( iobuf ); } @@ -3421,27 +3411,27 @@ static int tls_newdata_process_data ( struct tls_connection *tls ) { int rc; /* Move current buffer to end of list */ - iobuf = list_first_entry ( &tls->rx_data, struct io_buffer, list ); + iobuf = list_first_entry ( &tls->rx.data, struct io_buffer, list ); list_del ( &iobuf->list ); - list_add_tail ( &iobuf->list, &tls->rx_data ); + list_add_tail ( &iobuf->list, &tls->rx.data ); /* Continue receiving data if any space remains */ - iobuf = list_first_entry ( &tls->rx_data, struct io_buffer, list ); + iobuf = list_first_entry ( &tls->rx.data, struct io_buffer, list ); if ( iob_tailroom ( iobuf ) ) return 0; /* Process record */ - if ( ( rc = tls_new_ciphertext ( tls, &tls->rx_header, - &tls->rx_data ) ) != 0 ) + if ( ( rc = tls_new_ciphertext ( tls, &tls->rx.header, + &tls->rx.data ) ) != 0 ) return rc; /* Increment RX sequence number */ - tls->rx_seq += 1; + tls->rx.seq += 1; /* Return to header state */ - assert ( list_empty ( &tls->rx_data ) ); - tls->rx_state = TLS_RX_HEADER; - iob_unput ( &tls->rx_header_iobuf, sizeof ( tls->rx_header ) ); + assert ( list_empty ( &tls->rx.data ) ); + tls->rx.state = TLS_RX_HEADER; + iob_unput ( &tls->rx.iobuf, sizeof ( tls->rx.header ) ); return 0; } @@ -3480,13 +3470,13 @@ static int tls_cipherstream_deliver ( struct tls_connection *tls, while ( iob_len ( iobuf ) ) { /* Select buffer according to current state */ - switch ( tls->rx_state ) { + switch ( tls->rx.state ) { case TLS_RX_HEADER: - dest = &tls->rx_header_iobuf; + dest = &tls->rx.iobuf; process = tls_newdata_process_header; break; case TLS_RX_DATA: - dest = list_first_entry ( &tls->rx_data, + dest = list_first_entry ( &tls->rx.data, struct io_buffer, list ); assert ( dest != NULL ); process = tls_newdata_process_data; @@ -3550,15 +3540,13 @@ static struct interface_descriptor tls_cipherstream_desc = */ static void tls_validator_done ( struct tls_connection *tls, int rc ) { struct tls_session *session = tls->session; - struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending; - struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey; struct x509_certificate *cert; /* Mark validation as complete */ - pending_put ( &tls->validation ); + pending_put ( &tls->server.validation ); /* Close validator interface */ - intf_restart ( &tls->validator, rc ); + intf_restart ( &tls->server.validator, rc ); /* Check for validation failure */ if ( rc != 0 ) { @@ -3569,7 +3557,7 @@ static void tls_validator_done ( struct tls_connection *tls, int rc ) { DBGC ( tls, "TLS %p certificate validation succeeded\n", tls ); /* Extract first certificate */ - cert = x509_first ( tls->chain ); + cert = x509_first ( tls->server.chain ); assert ( cert != NULL ); /* Verify server name */ @@ -3579,21 +3567,16 @@ static void tls_validator_done ( struct tls_connection *tls, int rc ) { goto err; } - /* Initialise public key algorithm */ - if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx, - cert->subject.public_key.raw.data, - cert->subject.public_key.raw.len ) ) != 0 ) { - DBGC ( tls, "TLS %p cannot initialise public key: %s\n", - tls, strerror ( rc ) ); - goto err; - } + /* Extract the now trusted server public key */ + memcpy ( &tls->server.key, &cert->subject.public_key.raw, + sizeof ( tls->server.key ) ); /* Schedule Client Key Exchange, Change Cipher, and Finished */ - tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE | + tls->tx.pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE | TLS_TX_CHANGE_CIPHER | TLS_TX_FINISHED ); - if ( tls->certs ) { - tls->tx_pending |= ( TLS_TX_CERTIFICATE | + if ( tls->client.chain ) { + tls->tx.pending |= ( TLS_TX_CERTIFICATE | TLS_TX_CERTIFICATE_VERIFY ); } tls_tx_resume ( tls ); @@ -3612,7 +3595,8 @@ static struct interface_operation tls_validator_ops[] = { /** TLS certificate validator interface descriptor */ static struct interface_descriptor tls_validator_desc = - INTF_DESC ( struct tls_connection, validator, tls_validator_ops ); + INTF_DESC ( struct tls_connection, server.validator, + tls_validator_ops ); /****************************************************************************** * @@ -3636,7 +3620,7 @@ static void tls_tx_step ( struct tls_connection *tls ) { return; /* Send first pending transmission */ - if ( tls->tx_pending & TLS_TX_CLIENT_HELLO ) { + if ( tls->tx.pending & TLS_TX_CLIENT_HELLO ) { /* Serialise server negotiations within a session, to * provide a consistent view of session IDs and * session tickets. @@ -3644,7 +3628,7 @@ static void tls_tx_step ( struct tls_connection *tls ) { list_for_each_entry ( conn, &session->conn, list ) { if ( conn == tls ) break; - if ( is_pending ( &conn->server_negotiation ) ) + if ( is_pending ( &conn->server.negotiation ) ) return; } /* Record or generate session ID and associated master secret */ @@ -3658,8 +3642,8 @@ static void tls_tx_step ( struct tls_connection *tls ) { } else { /* No existing session: use a random session ID */ assert ( sizeof ( tls->session_id ) == - sizeof ( tls->client_random ) ); - memcpy ( tls->session_id, &tls->client_random, + sizeof ( tls->client.random ) ); + memcpy ( tls->session_id, &tls->client.random, sizeof ( tls->session_id ) ); tls->session_id_len = sizeof ( tls->session_id ); } @@ -3669,32 +3653,32 @@ static void tls_tx_step ( struct tls_connection *tls ) { tls, strerror ( rc ) ); goto err; } - tls->tx_pending &= ~TLS_TX_CLIENT_HELLO; - } else if ( tls->tx_pending & TLS_TX_CERTIFICATE ) { + tls->tx.pending &= ~TLS_TX_CLIENT_HELLO; + } else if ( tls->tx.pending & TLS_TX_CERTIFICATE ) { /* Send Certificate */ if ( ( rc = tls_send_certificate ( tls ) ) != 0 ) { DBGC ( tls, "TLS %p cold not send Certificate: %s\n", tls, strerror ( rc ) ); goto err; } - tls->tx_pending &= ~TLS_TX_CERTIFICATE; - } else if ( tls->tx_pending & TLS_TX_CLIENT_KEY_EXCHANGE ) { + tls->tx.pending &= ~TLS_TX_CERTIFICATE; + } else if ( tls->tx.pending & TLS_TX_CLIENT_KEY_EXCHANGE ) { /* Send Client Key Exchange */ if ( ( rc = tls_send_client_key_exchange ( tls ) ) != 0 ) { DBGC ( tls, "TLS %p could not send Client Key " "Exchange: %s\n", tls, strerror ( rc ) ); goto err; } - tls->tx_pending &= ~TLS_TX_CLIENT_KEY_EXCHANGE; - } else if ( tls->tx_pending & TLS_TX_CERTIFICATE_VERIFY ) { + tls->tx.pending &= ~TLS_TX_CLIENT_KEY_EXCHANGE; + } else if ( tls->tx.pending & TLS_TX_CERTIFICATE_VERIFY ) { /* Send Certificate Verify */ if ( ( rc = tls_send_certificate_verify ( tls ) ) != 0 ) { DBGC ( tls, "TLS %p could not send Certificate " "Verify: %s\n", tls, strerror ( rc ) ); goto err; } - tls->tx_pending &= ~TLS_TX_CERTIFICATE_VERIFY; - } else if ( tls->tx_pending & TLS_TX_CHANGE_CIPHER ) { + tls->tx.pending &= ~TLS_TX_CERTIFICATE_VERIFY; + } else if ( tls->tx.pending & TLS_TX_CHANGE_CIPHER ) { /* Send Change Cipher, and then change the cipher in use */ if ( ( rc = tls_send_change_cipher ( tls ) ) != 0 ) { DBGC ( tls, "TLS %p could not send Change Cipher: " @@ -3702,28 +3686,27 @@ static void tls_tx_step ( struct tls_connection *tls ) { goto err; } if ( ( rc = tls_change_cipher ( tls, - &tls->tx_cipherspec_pending, - &tls->tx_cipherspec )) != 0 ){ + &tls->tx.cipherspec ) ) != 0 ){ DBGC ( tls, "TLS %p could not activate TX cipher: " "%s\n", tls, strerror ( rc ) ); goto err; } - tls->tx_seq = 0; - tls->tx_pending &= ~TLS_TX_CHANGE_CIPHER; - } else if ( tls->tx_pending & TLS_TX_FINISHED ) { + tls->tx.seq = 0; + tls->tx.pending &= ~TLS_TX_CHANGE_CIPHER; + } else if ( tls->tx.pending & TLS_TX_FINISHED ) { /* Send Finished */ if ( ( rc = tls_send_finished ( tls ) ) != 0 ) { DBGC ( tls, "TLS %p could not send Finished: %s\n", tls, strerror ( rc ) ); goto err; } - tls->tx_pending &= ~TLS_TX_FINISHED; + tls->tx.pending &= ~TLS_TX_FINISHED; } /* Reschedule process if pending transmissions remain, * otherwise send notification of a window change. */ - if ( tls->tx_pending ) { + if ( tls->tx.pending ) { tls_tx_resume ( tls ); } else { xfer_window_changed ( &tls->plainstream ); @@ -3737,7 +3720,7 @@ static void tls_tx_step ( struct tls_connection *tls ) { /** TLS TX process descriptor */ static struct process_descriptor tls_process_desc = - PROC_DESC_ONCE ( struct tls_connection, process, tls_tx_step ); + PROC_DESC_ONCE ( struct tls_connection, tx.process, tls_tx_step ); /****************************************************************************** * @@ -3761,8 +3744,8 @@ static int tls_session ( struct tls_connection *tls, const char *name ) { /* Find existing matching session, if any */ list_for_each_entry ( session, &tls_sessions, list ) { if ( ( strcmp ( name, session->name ) == 0 ) && - ( tls->root == session->root ) && - ( tls->key == session->key ) ) { + ( tls->server.root == session->root ) && + ( tls->client.key == session->key ) ) { ref_get ( &session->refcnt ); tls->session = session; DBGC ( tls, "TLS %p joining session %s\n", tls, name ); @@ -3781,8 +3764,8 @@ static int tls_session ( struct tls_connection *tls, const char *name ) { name_copy = ( ( ( void * ) session ) + sizeof ( *session ) ); strcpy ( name_copy, name ); session->name = name_copy; - session->root = x509_root_get ( tls->root ); - session->key = privkey_get ( tls->key ); + session->root = x509_root_get ( tls->server.root ); + session->key = privkey_get ( tls->client.key ); INIT_LIST_HEAD ( &session->conn ); list_add ( &session->list, &tls_sessions ); @@ -3829,23 +3812,23 @@ int add_tls ( struct interface *xfer, const char *name, INIT_LIST_HEAD ( &tls->list ); intf_init ( &tls->plainstream, &tls_plainstream_desc, &tls->refcnt ); intf_init ( &tls->cipherstream, &tls_cipherstream_desc, &tls->refcnt ); - intf_init ( &tls->validator, &tls_validator_desc, &tls->refcnt ); - process_init_stopped ( &tls->process, &tls_process_desc, + intf_init ( &tls->server.validator, &tls_validator_desc, &tls->refcnt ); + process_init_stopped ( &tls->tx.process, &tls_process_desc, &tls->refcnt ); - tls->key = privkey_get ( key ? key : &private_key ); - tls->root = x509_root_get ( root ? root : &root_certificates ); + tls->client.key = privkey_get ( key ? key : &private_key ); + tls->server.root = x509_root_get ( root ? root : &root_certificates ); tls->version = TLS_VERSION_MAX; - tls_clear_cipher ( tls, &tls->tx_cipherspec ); - tls_clear_cipher ( tls, &tls->tx_cipherspec_pending ); - tls_clear_cipher ( tls, &tls->rx_cipherspec ); - tls_clear_cipher ( tls, &tls->rx_cipherspec_pending ); + tls_clear_cipher ( tls, &tls->tx.cipherspec.active ); + tls_clear_cipher ( tls, &tls->tx.cipherspec.pending ); + tls_clear_cipher ( tls, &tls->rx.cipherspec.active ); + tls_clear_cipher ( tls, &tls->rx.cipherspec.pending ); tls_clear_handshake ( tls ); - tls->client_random.gmt_unix_time = time ( NULL ); - iob_populate ( &tls->rx_header_iobuf, &tls->rx_header, 0, - sizeof ( tls->rx_header ) ); - INIT_LIST_HEAD ( &tls->rx_data ); - if ( ( rc = tls_generate_random ( tls, &tls->client_random.random, - ( sizeof ( tls->client_random.random ) ) ) ) != 0 ) { + tls->client.random.gmt_unix_time = time ( NULL ); + iob_populate ( &tls->rx.iobuf, &tls->rx.header, 0, + sizeof ( tls->rx.header ) ); + INIT_LIST_HEAD ( &tls->rx.data ); + if ( ( rc = tls_generate_random ( tls, &tls->client.random.random, + ( sizeof ( tls->client.random.random ) ) ) ) != 0 ) { goto err_random; } if ( ( rc = tls_session ( tls, name ) ) != 0 ) diff --git a/src/net/validator.c b/src/net/validator.c index 69c0df3..e1371d2 100644 --- a/src/net/validator.c +++ b/src/net/validator.c @@ -135,9 +135,11 @@ struct validator { * @ret name Validator name */ static const char * validator_name ( struct validator *validator ) { + struct x509_certificate *cert; - /* Use name of first certificate in chain */ - return x509_name ( x509_first ( validator->chain ) ); + /* Use name of first certificate in chain, if present */ + cert = x509_first ( validator->chain ); + return ( cert ? x509_name ( cert ) : "<empty>" ); } /** diff --git a/src/tests/cms_test.c b/src/tests/cms_test.c index f35fa20..fc4f6bd 100644 --- a/src/tests/cms_test.c +++ b/src/tests/cms_test.c @@ -36,30 +36,40 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <string.h> #include <ipxe/sha256.h> #include <ipxe/x509.h> +#include <ipxe/image.h> #include <ipxe/uaccess.h> +#include <ipxe/der.h> #include <ipxe/cms.h> +#include <ipxe/privkey.h> #include <ipxe/test.h> /** Fingerprint algorithm used for X.509 test certificates */ #define cms_test_algorithm sha256_algorithm -/** CMS test code blob */ -struct cms_test_code { - /** Data */ - const void *data; - /** Length of data */ - size_t len; +/** Test image */ +struct cms_test_image { + /** Image */ + struct image image; +}; + +/** Test CMS message */ +struct cms_test_message { + /** Message image */ + struct image image; + /** Parsed message */ + struct cms_message *cms; }; -/** CMS test signature */ -struct cms_test_signature { - /** Data */ +/** Test CMS key pair */ +struct cms_test_keypair { + /** Private key */ + struct private_key privkey; + /** Certificate data */ const void *data; - /** Length of data */ + /** Length of certificate data */ size_t len; - - /** Parsed signature */ - struct cms_signature *sig; + /** Parsed certificate */ + struct x509_certificate *cert; }; /** Define inline data */ @@ -68,24 +78,49 @@ struct cms_test_signature { /** Define inline fingerprint data */ #define FINGERPRINT(...) { __VA_ARGS__ } -/** Define a test code blob */ -#define SIGNED_CODE( name, DATA ) \ - static const uint8_t name ## _data[] = DATA; \ - static struct cms_test_code name = { \ - .data = name ## _data, \ - .len = sizeof ( name ## _data ), \ +/** Define a test image */ +#define IMAGE( NAME, DATA ) \ + static uint8_t NAME ## _data[] = DATA; \ + static struct cms_test_image NAME = { \ + .image = { \ + .refcnt = REF_INIT ( ref_no_free ), \ + .name = #NAME, \ + .data = ( userptr_t ) ( NAME ## _data ), \ + .len = sizeof ( NAME ## _data ), \ + }, \ + } + +/** Define a test message */ +#define MESSAGE( NAME, DATA ) \ + static const uint8_t NAME ## _data[] = DATA; \ + static struct cms_test_message NAME = { \ + .image = { \ + .refcnt = REF_INIT ( ref_no_free ), \ + .name = #NAME, \ + .type = &der_image_type, \ + .data = ( userptr_t ) ( NAME ## _data ), \ + .len = sizeof ( NAME ## _data ), \ + }, \ } -/** Define a test signature */ -#define SIGNATURE( name, DATA ) \ - static const uint8_t name ## _data[] = DATA; \ - static struct cms_test_signature name = { \ - .data = name ## _data, \ - .len = sizeof ( name ## _data ), \ +/** Define a test key pair */ +#define KEYPAIR( NAME, PRIVKEY, CERT ) \ + static uint8_t NAME ## _privkey[] = PRIVKEY; \ + static const uint8_t NAME ## _cert[] = CERT; \ + static struct cms_test_keypair NAME = { \ + .privkey = { \ + .refcnt = REF_INIT ( ref_no_free ), \ + .builder = { \ + .data = NAME ## _privkey, \ + .len = sizeof ( NAME ## _privkey ), \ + }, \ + }, \ + .data = NAME ## _cert, \ + .len = sizeof ( NAME ## _cert ), \ } /** Code that has been signed */ -SIGNED_CODE ( test_code, +IMAGE ( test_code, DATA ( 0x23, 0x21, 0x69, 0x70, 0x78, 0x65, 0x0a, 0x0a, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, @@ -97,7 +132,7 @@ SIGNED_CODE ( test_code, 0x65, 0x6c, 0x6c, 0x0a ) ); /** Code that has not been signed */ -SIGNED_CODE ( bad_code, +IMAGE ( bad_code, DATA ( 0x23, 0x21, 0x69, 0x70, 0x78, 0x65, 0x0a, 0x0a, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x6c, 0x69, 0x63, 0x69, 0x6f, @@ -107,8 +142,125 @@ SIGNED_CODE ( bad_code, 0x6f, 0x75, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x21, 0x0a, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x0a ) ); +/** Plaintext of encrypted code */ +IMAGE ( hidden_code, + DATA ( 0x23, 0x21, 0x69, 0x70, 0x78, 0x65, 0x0a, 0x0a, 0x65, 0x63, + 0x68, 0x6f, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, + 0x20, 0x61, 0x20, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x65, 0x64, 0x20, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x2e, 0x20, 0x20, 0x44, 0x6f, 0x20, + 0x61, 0x6e, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x79, + 0x6f, 0x75, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x21, 0x0a, 0x73, + 0x68, 0x65, 0x6c, 0x6c, 0x0a ) ); + +/** Code encrypted with AES-256-CBC */ +IMAGE ( hidden_code_cbc_dat, + DATA ( 0xaa, 0x63, 0x9f, 0x12, 0xeb, 0x1e, 0xdd, 0x9b, 0xb6, 0x4d, + 0x81, 0xd5, 0xba, 0x2d, 0x86, 0x7a, 0x1c, 0x39, 0x10, 0x60, + 0x43, 0xac, 0x1b, 0x4e, 0x43, 0xb7, 0x50, 0x5a, 0x6d, 0x7a, + 0x4b, 0xd8, 0x65, 0x3c, 0x3e, 0xbd, 0x40, 0x9e, 0xb2, 0xe1, + 0x7d, 0x80, 0xf8, 0x22, 0x50, 0xf7, 0x32, 0x3a, 0x43, 0xf9, + 0xdf, 0xa6, 0xab, 0xa4, 0xb3, 0xdd, 0x27, 0x88, 0xd9, 0xb0, + 0x99, 0xb5, 0x7a, 0x89, 0x6c, 0xb7, 0x63, 0x45, 0x42, 0x7d, + 0xbe, 0x43, 0xab, 0x7e, 0x6c, 0x0c, 0xd5, 0xba, 0x9e, 0x37 ) ); + +/** Envelope for code encrypted with AES-256-CBC */ +MESSAGE ( hidden_code_cbc_env, + DATA ( 0x30, 0x82, 0x01, 0x70, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x07, 0x03, 0xa0, 0x82, 0x01, 0x61, 0x30, + 0x82, 0x01, 0x5d, 0x02, 0x01, 0x00, 0x31, 0x82, 0x01, 0x2a, + 0x30, 0x82, 0x01, 0x26, 0x02, 0x01, 0x00, 0x30, 0x81, 0x8e, + 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, + 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, + 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, + 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, + 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, 0x41, 0x02, + 0x01, 0x08, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x81, 0x80, + 0x10, 0x26, 0x94, 0x97, 0xe5, 0x84, 0x53, 0xf9, 0x03, 0xc4, + 0xf6, 0xc1, 0x55, 0xf5, 0x00, 0x23, 0xb9, 0x80, 0x20, 0x85, + 0xd2, 0xf2, 0xc4, 0x61, 0xdb, 0x73, 0x8d, 0xe1, 0xa1, 0x73, + 0x7d, 0x31, 0x12, 0xb7, 0xac, 0xa4, 0xe0, 0x40, 0x10, 0xcf, + 0xd5, 0x55, 0x70, 0x75, 0x9f, 0x7b, 0x61, 0xd3, 0x9e, 0xc6, + 0x58, 0x78, 0x05, 0x66, 0xc1, 0x86, 0x2f, 0x00, 0xcd, 0xe9, + 0x32, 0x63, 0x7c, 0x95, 0xd7, 0x75, 0x46, 0xde, 0x76, 0x7d, + 0x49, 0x64, 0x86, 0xd6, 0xeb, 0x0f, 0x1c, 0x01, 0x20, 0xb9, + 0xb9, 0x42, 0xc4, 0x20, 0x1f, 0x3f, 0xae, 0x5f, 0xb9, 0xd0, + 0xb6, 0x49, 0xcc, 0x4c, 0xd9, 0xcb, 0x36, 0xa4, 0x2f, 0xb1, + 0x97, 0x40, 0xf3, 0xe7, 0x19, 0x88, 0x93, 0x58, 0x61, 0x31, + 0xac, 0x9a, 0x93, 0x6e, 0x79, 0x31, 0x3a, 0x79, 0xa4, 0x20, + 0x38, 0x17, 0x92, 0x40, 0x7c, 0x98, 0xea, 0x86, 0x30, 0x2a, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x01, 0x30, 0x1d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, + 0x03, 0x04, 0x01, 0x2a, 0x04, 0x10, 0xd8, 0x80, 0xc5, 0xfa, + 0xc3, 0x25, 0xa0, 0x22, 0xb5, 0x6c, 0x0c, 0x27, 0x2c, 0xe9, + 0xba, 0xcf ) ); + +/** Code encrypted with AES-256-GCM (no block padding) */ +IMAGE ( hidden_code_gcm_dat, + DATA ( 0x0c, 0x96, 0xa6, 0x54, 0x9a, 0xc2, 0x24, 0x89, 0x15, 0x00, + 0x90, 0xe1, 0x35, 0xca, 0x4a, 0x84, 0x8e, 0x0b, 0xc3, 0x5e, + 0xc0, 0x61, 0x61, 0xbd, 0x2e, 0x69, 0x84, 0x7a, 0x2f, 0xf6, + 0xbe, 0x39, 0x04, 0x0a, 0x8d, 0x91, 0x6b, 0xaf, 0x63, 0xd4, + 0x03, 0xf1, 0x72, 0x38, 0xee, 0x27, 0xd6, 0x5a, 0xae, 0x15, + 0xd5, 0xec, 0xb6, 0xb6, 0x4f, 0x6f, 0xf6, 0x76, 0x22, 0x74, + 0xca, 0x72, 0x0b, 0xfa, 0x6a, 0x0e, 0x4a, 0x3e, 0x8c, 0x60, + 0x78, 0x24, 0x48, 0x58, 0xdd ) ); + +/** Envelope for code encrypted with AES-256-GCM (no block padding) */ +MESSAGE ( hidden_code_gcm_env, + DATA ( 0x30, 0x82, 0x01, 0x85, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x17, 0xa0, 0x82, 0x01, + 0x74, 0x30, 0x82, 0x01, 0x70, 0x02, 0x01, 0x00, 0x31, 0x82, + 0x01, 0x2a, 0x30, 0x82, 0x01, 0x26, 0x02, 0x01, 0x00, 0x30, + 0x81, 0x8e, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, + 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, + 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, + 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, + 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, + 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, + 0x41, 0x02, 0x01, 0x08, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, + 0x81, 0x80, 0x7e, 0xbc, 0xba, 0xee, 0xfa, 0x50, 0x46, 0xee, + 0xed, 0xf1, 0x54, 0xe1, 0x46, 0xeb, 0x57, 0x3e, 0x76, 0xd7, + 0x8f, 0xe3, 0x26, 0x42, 0x3d, 0x28, 0xf9, 0xdc, 0x20, 0xe6, + 0x27, 0x3b, 0x89, 0xcb, 0xab, 0xd5, 0xad, 0xc2, 0xf0, 0x4f, + 0xa8, 0xb9, 0x77, 0x5b, 0x6c, 0xe6, 0x34, 0x22, 0x73, 0x5b, + 0xa4, 0x8e, 0x1c, 0xc2, 0xf8, 0x50, 0xef, 0xe5, 0xcf, 0x80, + 0x16, 0x79, 0x6b, 0x0f, 0xa7, 0xfd, 0xdc, 0x60, 0x9c, 0x94, + 0x60, 0xa6, 0x12, 0x5a, 0xfb, 0xc2, 0xc8, 0x4c, 0x64, 0x83, + 0x99, 0x73, 0xfc, 0xa1, 0xf8, 0xa5, 0x82, 0x75, 0xba, 0x53, + 0xeb, 0xc8, 0x94, 0x0e, 0x29, 0x23, 0x9a, 0x2b, 0xa6, 0x63, + 0x2d, 0x5b, 0x9f, 0x38, 0x70, 0x21, 0xe8, 0xe9, 0xa6, 0xcf, + 0xf2, 0xbe, 0x66, 0xf4, 0xcc, 0x91, 0x01, 0x4f, 0x04, 0x00, + 0x4a, 0x55, 0xc9, 0x42, 0x76, 0xd4, 0x3f, 0x65, 0x0c, 0x76, + 0x30, 0x2b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x07, 0x01, 0x30, 0x1e, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, 0x01, 0x2e, 0x30, 0x11, 0x04, 0x0c, + 0x72, 0xb5, 0x14, 0xfb, 0x05, 0x78, 0x70, 0x1c, 0xf4, 0x4b, + 0xba, 0xbf, 0x02, 0x01, 0x10, 0x04, 0x10, 0x1e, 0x44, 0xda, + 0x5c, 0x75, 0x7e, 0x4f, 0xa7, 0xe7, 0xd9, 0x98, 0x80, 0x9c, + 0x25, 0x6a, 0xfb ) ); + /** Valid signature */ -SIGNATURE ( codesigned_sig, +MESSAGE ( codesigned_sig, DATA ( 0x30, 0x82, 0x0c, 0x41, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x0c, 0x32, 0x30, 0x82, 0x0c, 0x2e, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07, @@ -426,7 +578,7 @@ SIGNATURE ( codesigned_sig, 0xbf ) ); /** Signature with a broken certificate chain */ -SIGNATURE ( brokenchain_sig, +MESSAGE ( brokenchain_sig, DATA ( 0x30, 0x82, 0x09, 0x8a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0x7b, 0x30, 0x82, 0x09, 0x77, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07, @@ -674,7 +826,7 @@ SIGNATURE ( brokenchain_sig, 0xf9, 0x71, 0x64, 0x03, 0x05, 0xbf ) ); /** Signature generated with a non-code-signing certificate */ -SIGNATURE ( genericsigned_sig, +MESSAGE ( genericsigned_sig, DATA ( 0x30, 0x82, 0x0c, 0x2f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x0c, 0x20, 0x30, 0x82, 0x0c, 0x1c, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07, @@ -990,7 +1142,7 @@ SIGNATURE ( genericsigned_sig, 0x7e, 0x7c, 0x99 ) ); /** Signature generated with a non-signing certificate */ -SIGNATURE ( nonsigned_sig, +MESSAGE ( nonsigned_sig, DATA ( 0x30, 0x82, 0x0c, 0x12, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x0c, 0x03, 0x30, 0x82, 0x0b, 0xff, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07, @@ -1302,6 +1454,138 @@ SIGNATURE ( nonsigned_sig, 0x5d, 0x70, 0x47, 0x54, 0xbc, 0x15, 0xad, 0x9c, 0xe8, 0x90, 0x52, 0x3e, 0x49, 0x86 ) ); +/** Client certificate and private key */ +KEYPAIR ( client_keypair, + DATA ( 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x04, 0x82, 0x02, 0x61, 0x30, 0x82, 0x02, 0x5d, + 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xb7, 0x9f, 0xb5, + 0x90, 0xfa, 0x47, 0x25, 0xee, 0x3b, 0x04, 0x02, 0x4f, 0xd4, + 0x1d, 0x62, 0x46, 0x9d, 0xce, 0x79, 0x3a, 0x80, 0x3a, 0xc4, + 0x06, 0x6a, 0x67, 0xd4, 0x3a, 0x61, 0x71, 0xcd, 0xb3, 0xcc, + 0x1b, 0xfc, 0x2f, 0x17, 0xa8, 0xf2, 0x26, 0x9e, 0x54, 0xd3, + 0x49, 0x81, 0x22, 0xa9, 0x72, 0x4c, 0xe8, 0x92, 0xb7, 0x1e, + 0x44, 0x8f, 0xa9, 0x4d, 0x83, 0x0b, 0x89, 0x2a, 0xc7, 0xb3, + 0xad, 0x54, 0x32, 0x76, 0x62, 0x1e, 0xe5, 0xbe, 0xc1, 0xa8, + 0x7a, 0x2b, 0xf0, 0xa9, 0x9a, 0xfb, 0xb8, 0x18, 0x0c, 0x30, + 0x5a, 0x13, 0x9c, 0x21, 0x26, 0x96, 0x4f, 0x39, 0x98, 0x64, + 0x41, 0x3b, 0x94, 0xc8, 0xe3, 0xb7, 0x8c, 0x33, 0x9e, 0xd0, + 0x71, 0xd0, 0x2f, 0xe3, 0x7d, 0x2c, 0x57, 0x27, 0x42, 0x26, + 0xd9, 0x2c, 0xb4, 0x55, 0xd5, 0x66, 0xb7, 0xbf, 0x00, 0xa1, + 0xcc, 0x61, 0x19, 0x99, 0x61, 0x02, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x81, 0x80, 0x50, 0x63, 0x2f, 0xe6, 0xb7, 0x5a, 0xfc, + 0x85, 0x0d, 0xfb, 0x14, 0x54, 0x04, 0x65, 0x94, 0xc7, 0x9b, + 0x80, 0x6f, 0xdc, 0x27, 0x95, 0x12, 0x8a, 0x48, 0x7d, 0x0a, + 0x11, 0x40, 0xe5, 0xc4, 0x8b, 0x29, 0x19, 0x3b, 0x4f, 0x16, + 0x89, 0x94, 0xf1, 0x49, 0x31, 0x93, 0x8a, 0x43, 0x69, 0x7c, + 0x4b, 0x18, 0xd6, 0x5c, 0x9c, 0xa4, 0x38, 0x99, 0xb8, 0x21, + 0xc1, 0xf4, 0x03, 0xe9, 0xe1, 0xa1, 0x8b, 0xcb, 0x51, 0x4f, + 0x64, 0x68, 0x1c, 0x73, 0xc0, 0x0d, 0xd2, 0xcd, 0x87, 0xcc, + 0x45, 0xe8, 0xbf, 0x88, 0xea, 0x6c, 0x42, 0xfa, 0x03, 0x7a, + 0x29, 0xd2, 0xcf, 0xf1, 0xcb, 0xae, 0xea, 0xfb, 0x50, 0xf2, + 0xbd, 0x02, 0x4f, 0x2f, 0x4f, 0xba, 0x82, 0xa9, 0xde, 0x60, + 0x56, 0xd4, 0x07, 0x73, 0xdf, 0x12, 0x09, 0x73, 0x7b, 0x54, + 0x35, 0xc6, 0x28, 0x10, 0xb0, 0xbd, 0xc8, 0xe1, 0x8f, 0xb2, + 0x41, 0x02, 0x41, 0x00, 0xd8, 0xf9, 0x6c, 0x70, 0x56, 0x3c, + 0x74, 0x44, 0x53, 0x13, 0xed, 0x92, 0xab, 0xbc, 0x0c, 0x5c, + 0x66, 0x2c, 0xd7, 0xed, 0x10, 0x82, 0xe3, 0xe3, 0x2e, 0xda, + 0x4d, 0x3e, 0x1f, 0xc0, 0x50, 0xa8, 0xf2, 0xce, 0x77, 0xa9, + 0xae, 0xa2, 0x2d, 0x49, 0x6a, 0x6f, 0x01, 0xe3, 0xca, 0x57, + 0xf4, 0xcc, 0xb4, 0x3f, 0xd9, 0xc3, 0x58, 0x54, 0xe7, 0x62, + 0xfc, 0x40, 0xc8, 0xba, 0x18, 0x0d, 0xfe, 0x89, 0x02, 0x41, + 0x00, 0xd8, 0xa6, 0xaa, 0x4b, 0xcc, 0xcf, 0xc4, 0x47, 0x84, + 0x13, 0x39, 0x5b, 0x2e, 0xcb, 0xe0, 0x41, 0xd0, 0x2c, 0x96, + 0x58, 0x73, 0xab, 0xf6, 0x41, 0x0c, 0x7b, 0xbe, 0x60, 0xa1, + 0xcb, 0x00, 0x1a, 0xb0, 0x4b, 0xc1, 0xf5, 0x27, 0x43, 0x97, + 0x87, 0x30, 0x3c, 0x27, 0xa3, 0xe3, 0xf1, 0xa7, 0x45, 0x01, + 0xe2, 0x1c, 0x43, 0xe9, 0x48, 0x43, 0x76, 0x24, 0x4b, 0x2b, + 0xc7, 0x67, 0x3e, 0x4e, 0x19, 0x02, 0x40, 0x6a, 0x43, 0x96, + 0x31, 0x5a, 0x7a, 0xd7, 0x32, 0x93, 0x41, 0xa2, 0x4c, 0x00, + 0x21, 0xe4, 0x27, 0xe8, 0xbe, 0xb3, 0xad, 0xde, 0x35, 0x4c, + 0xa8, 0xfa, 0x4c, 0x5e, 0x22, 0x3b, 0xe8, 0xb3, 0x58, 0x5b, + 0x3a, 0x75, 0x6e, 0xbc, 0x21, 0x9f, 0x6e, 0x62, 0x5b, 0x25, + 0xa0, 0xcb, 0x7b, 0xd2, 0x5f, 0xe3, 0x33, 0x96, 0x52, 0x4e, + 0xd3, 0x9e, 0x53, 0x63, 0x59, 0xd3, 0x35, 0x19, 0x0c, 0xd9, + 0x89, 0x02, 0x41, 0x00, 0x8f, 0x8d, 0xb7, 0xaf, 0x6c, 0x31, + 0x8b, 0x0c, 0x1c, 0x1e, 0xa4, 0xd5, 0x9f, 0x67, 0x65, 0xdc, + 0x15, 0xf5, 0x45, 0x55, 0xac, 0xa7, 0x98, 0x0f, 0x38, 0x17, + 0x52, 0x69, 0x33, 0x2b, 0x90, 0x91, 0x1e, 0x99, 0xc4, 0x16, + 0x0e, 0x03, 0x42, 0x87, 0x48, 0x55, 0xc3, 0xaa, 0x5b, 0xe2, + 0x86, 0x84, 0x3a, 0x20, 0x39, 0xbc, 0x61, 0xfa, 0x09, 0x01, + 0x62, 0x41, 0x10, 0xec, 0x1a, 0xa3, 0xf5, 0x19, 0x02, 0x41, + 0x00, 0x98, 0x04, 0xc8, 0x8e, 0xd0, 0xfa, 0xe5, 0xab, 0x8a, + 0x1c, 0x4a, 0xc2, 0xf7, 0xd4, 0xad, 0x52, 0x51, 0x81, 0xa6, + 0x59, 0x62, 0x84, 0x16, 0x82, 0xf2, 0x5d, 0xd0, 0x5d, 0x4a, + 0xcf, 0x94, 0x2f, 0x13, 0x47, 0xd4, 0xc2, 0x7f, 0x89, 0x2e, + 0x40, 0xf5, 0xfc, 0xf8, 0x82, 0xc6, 0x53, 0xd4, 0x75, 0x32, + 0x47, 0x1d, 0xcf, 0xd1, 0xae, 0x35, 0x41, 0x7a, 0xdc, 0x10, + 0x0c, 0xc2, 0xd6, 0xe1, 0xd5 ), + DATA ( 0x30, 0x82, 0x02, 0x7f, 0x30, 0x82, 0x01, 0xe8, 0x02, 0x01, + 0x08, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, + 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, + 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, + 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, + 0x61, 0x66, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x32, + 0x34, 0x30, 0x38, 0x32, 0x39, 0x32, 0x32, 0x31, 0x39, 0x35, + 0x38, 0x5a, 0x17, 0x0d, 0x32, 0x35, 0x30, 0x38, 0x32, 0x39, + 0x32, 0x32, 0x31, 0x39, 0x35, 0x38, 0x5a, 0x30, 0x81, 0x86, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, + 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, + 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, + 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, + 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, + 0x6f, 0x72, 0x67, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x14, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, 0x65, + 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, + 0x81, 0x81, 0x00, 0xb7, 0x9f, 0xb5, 0x90, 0xfa, 0x47, 0x25, + 0xee, 0x3b, 0x04, 0x02, 0x4f, 0xd4, 0x1d, 0x62, 0x46, 0x9d, + 0xce, 0x79, 0x3a, 0x80, 0x3a, 0xc4, 0x06, 0x6a, 0x67, 0xd4, + 0x3a, 0x61, 0x71, 0xcd, 0xb3, 0xcc, 0x1b, 0xfc, 0x2f, 0x17, + 0xa8, 0xf2, 0x26, 0x9e, 0x54, 0xd3, 0x49, 0x81, 0x22, 0xa9, + 0x72, 0x4c, 0xe8, 0x92, 0xb7, 0x1e, 0x44, 0x8f, 0xa9, 0x4d, + 0x83, 0x0b, 0x89, 0x2a, 0xc7, 0xb3, 0xad, 0x54, 0x32, 0x76, + 0x62, 0x1e, 0xe5, 0xbe, 0xc1, 0xa8, 0x7a, 0x2b, 0xf0, 0xa9, + 0x9a, 0xfb, 0xb8, 0x18, 0x0c, 0x30, 0x5a, 0x13, 0x9c, 0x21, + 0x26, 0x96, 0x4f, 0x39, 0x98, 0x64, 0x41, 0x3b, 0x94, 0xc8, + 0xe3, 0xb7, 0x8c, 0x33, 0x9e, 0xd0, 0x71, 0xd0, 0x2f, 0xe3, + 0x7d, 0x2c, 0x57, 0x27, 0x42, 0x26, 0xd9, 0x2c, 0xb4, 0x55, + 0xd5, 0x66, 0xb7, 0xbf, 0x00, 0xa1, 0xcc, 0x61, 0x19, 0x99, + 0x61, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x03, 0x81, 0x81, 0x00, 0x22, 0x6e, 0x8b, 0x81, 0xc3, + 0x13, 0x89, 0x31, 0xcc, 0x6d, 0x44, 0xa5, 0x77, 0x31, 0x79, + 0xff, 0xea, 0x8a, 0x4e, 0xe6, 0xb6, 0x4a, 0xf0, 0x01, 0xd3, + 0x9f, 0xd7, 0x23, 0x14, 0x4c, 0xdd, 0xa3, 0xdf, 0xd6, 0x2b, + 0x2a, 0xc4, 0xba, 0xf7, 0xef, 0xfd, 0x78, 0xd5, 0xd7, 0xfd, + 0xd7, 0x77, 0x17, 0x20, 0x4f, 0xf3, 0x94, 0xd6, 0x74, 0xd5, + 0x09, 0x54, 0x16, 0x49, 0x6e, 0xd9, 0x41, 0xa7, 0x43, 0x77, + 0x7f, 0xef, 0xd3, 0xd7, 0xbb, 0x8b, 0xf0, 0x7d, 0x1f, 0x00, + 0x4a, 0xac, 0x18, 0xff, 0x20, 0x32, 0xd1, 0x1c, 0x13, 0xf2, + 0xe0, 0xd7, 0x70, 0xec, 0xb6, 0xf7, 0xa3, 0x42, 0xa1, 0x64, + 0x26, 0x30, 0x9f, 0x47, 0xd4, 0xfb, 0xfb, 0x06, 0xdb, 0x0b, + 0xb3, 0x27, 0xe6, 0x04, 0xe2, 0x94, 0x35, 0x8b, 0xa5, 0xfd, + 0x80, 0x1d, 0xa6, 0x72, 0x32, 0x30, 0x99, 0x6c, 0xbf, 0xd3, + 0x26, 0xa3, 0x8a ) ); + /** iPXE self-test root CA certificate */ static uint8_t root_crt_fingerprint[] = FINGERPRINT ( 0x71, 0x5d, 0x51, 0x37, 0x5e, 0x18, 0xb3, 0xbc, @@ -1345,26 +1629,55 @@ static time_t test_time = 1332374737ULL; /* Thu Mar 22 00:05:37 2012 */ static time_t test_expired = 1375573111ULL; /* Sat Aug 3 23:38:31 2013 */ /** - * Report signature parsing test result + * Report message parsing test result * - * @v sgn Test signature + * @v msg Test message * @v file Test code file * @v line Test code line */ -static void cms_signature_okx ( struct cms_test_signature *sgn, - const char *file, unsigned int line ) { +static void cms_message_okx ( struct cms_test_message *msg, + const char *file, unsigned int line ) { + const void *data = ( ( void * ) msg->image.data ); - okx ( cms_signature ( sgn->data, sgn->len, &sgn->sig ) == 0, + /* Fix up image data pointer */ + msg->image.data = virt_to_user ( data ); + + /* Check ability to parse message */ + okx ( cms_message ( &msg->image, &msg->cms ) == 0, file, line ); + + /* Reset image data pointer */ + msg->image.data = ( ( userptr_t ) data ); +} +#define cms_message_ok( msg ) \ + cms_message_okx ( msg, __FILE__, __LINE__ ) + +/** + * Report key pair parsing test result + * + * @v keypair Test key pair + * @v file Test code file + * @v line Test code line + */ +static void cms_keypair_okx ( struct cms_test_keypair *keypair, + const char *file, unsigned int line ) { + + /* Check ability to parse certificate */ + okx ( x509_certificate ( keypair->data, keypair->len, + &keypair->cert ) == 0, file, line ); + okx ( keypair->cert != NULL, file, line ); + + /* Check certificate can be identified by public key */ + okx ( x509_find_key ( NULL, &keypair->privkey ) == keypair->cert, file, line ); } -#define cms_signature_ok( sgn ) \ - cms_signature_okx ( sgn, __FILE__, __LINE__ ) +#define cms_keypair_ok( keypair ) \ + cms_keypair_okx ( keypair, __FILE__, __LINE__ ) /** * Report signature verification test result * - * @v sgn Test signature - * @v code Test signed code + * @v msg Test signature message + * @v img Test signed image * @v name Test verification name * @v time Test verification time * @v store Test certificate store @@ -1372,25 +1685,36 @@ static void cms_signature_okx ( struct cms_test_signature *sgn, * @v file Test code file * @v line Test code line */ -static void cms_verify_okx ( struct cms_test_signature *sgn, - struct cms_test_code *code, const char *name, +static void cms_verify_okx ( struct cms_test_message *msg, + struct cms_test_image *img, const char *name, time_t time, struct x509_chain *store, struct x509_root *root, const char *file, unsigned int line ) { + const void *data = ( ( void * ) img->image.data ); + + /* Fix up image data pointer */ + img->image.data = virt_to_user ( data ); + + /* Invalidate any certificates from previous tests */ + x509_invalidate_chain ( msg->cms->certificates ); - x509_invalidate_chain ( sgn->sig->certificates ); - okx ( cms_verify ( sgn->sig, virt_to_user ( code->data ), code->len, - name, time, store, root ) == 0, file, line ); + /* Check ability to verify signature */ + okx ( cms_verify ( msg->cms, &img->image, name, time, store, + root ) == 0, file, line ); + okx ( img->image.flags & IMAGE_TRUSTED, file, line ); + + /* Reset image data pointer */ + img->image.data = ( ( userptr_t ) data ); } -#define cms_verify_ok( sgn, code, name, time, store, root ) \ - cms_verify_okx ( sgn, code, name, time, store, root, \ +#define cms_verify_ok( msg, img, name, time, store, root ) \ + cms_verify_okx ( msg, img, name, time, store, root, \ __FILE__, __LINE__ ) /** * Report signature verification failure test result * - * @v sgn Test signature - * @v code Test signed code + * @v msg Test signature message + * @v img Test signed image * @v name Test verification name * @v time Test verification time * @v store Test certificate store @@ -1398,31 +1722,80 @@ static void cms_verify_okx ( struct cms_test_signature *sgn, * @v file Test code file * @v line Test code line */ -static void cms_verify_fail_okx ( struct cms_test_signature *sgn, - struct cms_test_code *code, const char *name, +static void cms_verify_fail_okx ( struct cms_test_message *msg, + struct cms_test_image *img, const char *name, time_t time, struct x509_chain *store, struct x509_root *root, const char *file, unsigned int line ) { + const void *data = ( ( void * ) img->image.data ); + + /* Fix up image data pointer */ + img->image.data = virt_to_user ( data ); + + /* Invalidate any certificates from previous tests */ + x509_invalidate_chain ( msg->cms->certificates ); - x509_invalidate_chain ( sgn->sig->certificates ); - okx ( cms_verify ( sgn->sig, virt_to_user ( code->data ), code->len, - name, time, store, root ) != 0, file, line ); + /* Check inability to verify signature */ + okx ( cms_verify ( msg->cms, &img->image, name, time, store, + root ) != 0, file, line ); + okx ( ! ( img->image.flags & IMAGE_TRUSTED ), file, line ); + + /* Reset image data pointer */ + img->image.data = ( ( userptr_t ) data ); } -#define cms_verify_fail_ok( sgn, code, name, time, store, root ) \ - cms_verify_fail_okx ( sgn, code, name, time, store, root, \ +#define cms_verify_fail_ok( msg, img, name, time, store, root ) \ + cms_verify_fail_okx ( msg, img, name, time, store, root, \ __FILE__, __LINE__ ) /** + * Report decryption test result + * + * @v img Encrypted data image + * @v envelope Envelope message + * @v keypair Key pair + * @v expected Expected plaintext image + * @v file Test code file + * @v line Test code line + */ +static void cms_decrypt_okx ( struct cms_test_image *img, + struct cms_test_message *envelope, + struct cms_test_keypair *keypair, + struct cms_test_image *expected, + const char *file, unsigned int line ) { + const void *data = ( ( void * ) img->image.data ); + + /* Fix up image data pointer */ + img->image.data = virt_to_user ( data ); + + /* Check ability to decrypt image */ + okx ( cms_decrypt ( envelope->cms, &img->image, NULL, + &keypair->privkey ) == 0, file, line ); + + /* Check decrypted image matches expected plaintext */ + okx ( img->image.len == expected->image.len, file, line ); + okx ( memcmp_user ( img->image.data, 0, expected->image.data, 0, + expected->image.len ) == 0, file, line ); +} +#define cms_decrypt_ok( data, envelope, keypair, expected ) \ + cms_decrypt_okx ( data, envelope, keypair, expected, \ + __FILE__, __LINE__ ) + +/** * Perform CMS self-tests * */ static void cms_test_exec ( void ) { - /* Check that all signatures can be parsed */ - cms_signature_ok ( &codesigned_sig ); - cms_signature_ok ( &brokenchain_sig ); - cms_signature_ok ( &genericsigned_sig ); - cms_signature_ok ( &nonsigned_sig ); + /* Check that all key pairs can be parsed */ + cms_keypair_ok ( &client_keypair ); + + /* Check that all messages can be parsed */ + cms_message_ok ( &codesigned_sig ); + cms_message_ok ( &brokenchain_sig ); + cms_message_ok ( &genericsigned_sig ); + cms_message_ok ( &nonsigned_sig ); + cms_message_ok ( &hidden_code_cbc_env ); + cms_message_ok ( &hidden_code_gcm_env ); /* Check good signature */ cms_verify_ok ( &codesigned_sig, &test_code, "codesign.test.ipxe.org", @@ -1459,14 +1832,27 @@ static void cms_test_exec ( void ) { cms_verify_fail_ok ( &codesigned_sig, &test_code, NULL, test_expired, &empty_store, &test_root ); + /* Check CBC decryption (with padding) */ + cms_decrypt_ok ( &hidden_code_cbc_dat, &hidden_code_cbc_env, + &client_keypair, &hidden_code ); + + /* Check GCM decryption (no padding) */ + cms_decrypt_ok ( &hidden_code_gcm_dat, &hidden_code_gcm_env, + &client_keypair, &hidden_code ); + /* Sanity check */ assert ( list_empty ( &empty_store.links ) ); - /* Drop signature references */ - cms_put ( nonsigned_sig.sig ); - cms_put ( genericsigned_sig.sig ); - cms_put ( brokenchain_sig.sig ); - cms_put ( codesigned_sig.sig ); + /* Drop message references */ + cms_put ( hidden_code_gcm_env.cms ); + cms_put ( hidden_code_cbc_env.cms ); + cms_put ( nonsigned_sig.cms ); + cms_put ( genericsigned_sig.cms ); + cms_put ( brokenchain_sig.cms ); + cms_put ( codesigned_sig.cms ); + + /* Drop certificate references */ + x509_put ( client_keypair.cert ); } /** CMS self-test */ diff --git a/src/tests/pubkey_test.c b/src/tests/pubkey_test.c new file mode 100644 index 0000000..ff318bf --- /dev/null +++ b/src/tests/pubkey_test.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2024 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 ); + +/** @file + * + * Public key self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <ipxe/crypto.h> +#include <ipxe/test.h> +#include "pubkey_test.h" + +/** + * Report public key encryption and decryption test result + * + * @v test Public key encryption and decryption test + * @v file Test code file + * @v line Test code line + */ +void pubkey_okx ( struct pubkey_test *test, const char *file, + unsigned int line ) { + struct pubkey_algorithm *pubkey = test->pubkey; + size_t max_len = pubkey_max_len ( pubkey, &test->private ); + uint8_t encrypted[max_len]; + uint8_t decrypted[max_len]; + int encrypted_len; + int decrypted_len; + + /* Test decrypting with private key to obtain known plaintext */ + decrypted_len = pubkey_decrypt ( pubkey, &test->private, + test->ciphertext, test->ciphertext_len, + decrypted ); + okx ( decrypted_len == ( ( int ) test->plaintext_len ), file, line ); + okx ( memcmp ( decrypted, test->plaintext, test->plaintext_len ) == 0, + file, line ); + + /* Test encrypting with private key and decrypting with public key */ + encrypted_len = pubkey_encrypt ( pubkey, &test->private, + test->plaintext, test->plaintext_len, + encrypted ); + okx ( encrypted_len >= 0, file, line ); + decrypted_len = pubkey_decrypt ( pubkey, &test->public, encrypted, + encrypted_len, decrypted ); + okx ( decrypted_len == ( ( int ) test->plaintext_len ), file, line ); + okx ( memcmp ( decrypted, test->plaintext, test->plaintext_len ) == 0, + file, line ); + + /* Test encrypting with public key and decrypting with private key */ + encrypted_len = pubkey_encrypt ( pubkey, &test->public, + test->plaintext, test->plaintext_len, + encrypted ); + okx ( encrypted_len >= 0, file, line ); + decrypted_len = pubkey_decrypt ( pubkey, &test->private, encrypted, + encrypted_len, decrypted ); + okx ( decrypted_len == ( ( int ) test->plaintext_len ), file, line ); + okx ( memcmp ( decrypted, test->plaintext, test->plaintext_len ) == 0, + file, line ); +} + +/** + * Report public key signature test result + * + * @v test Public key signature test + * @v file Test code file + * @v line Test code line + */ +void pubkey_sign_okx ( struct pubkey_sign_test *test, const char *file, + unsigned int line ) { + struct pubkey_algorithm *pubkey = test->pubkey; + struct digest_algorithm *digest = test->digest; + size_t max_len = pubkey_max_len ( pubkey, &test->private ); + uint8_t bad[test->signature_len]; + uint8_t digestctx[digest->ctxsize ]; + uint8_t digestout[digest->digestsize]; + uint8_t signature[max_len]; + int signature_len; + + /* Construct digest over plaintext */ + digest_init ( digest, digestctx ); + digest_update ( digest, digestctx, test->plaintext, + test->plaintext_len ); + digest_final ( digest, digestctx, digestout ); + + /* Test signing using private key */ + signature_len = pubkey_sign ( pubkey, &test->private, digest, + digestout, signature ); + okx ( signature_len == ( ( int ) test->signature_len ), file, line ); + okx ( memcmp ( signature, test->signature, test->signature_len ) == 0, + file, line ); + + /* Test verification using public key */ + okx ( pubkey_verify ( pubkey, &test->public, digest, digestout, + test->signature, test->signature_len ) == 0, + file, line ); + + /* Test verification failure of modified signature */ + memcpy ( bad, test->signature, test->signature_len ); + bad[ test->signature_len / 2 ] ^= 0x40; + okx ( pubkey_verify ( pubkey, &test->public, digest, digestout, + bad, sizeof ( bad ) ) != 0, file, line ); +} diff --git a/src/tests/pubkey_test.h b/src/tests/pubkey_test.h index cd65b87..20bb943 100644 --- a/src/tests/pubkey_test.h +++ b/src/tests/pubkey_test.h @@ -7,169 +7,151 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/crypto.h> #include <ipxe/test.h> -/** - * Report public key decryption test result - * - * @v pubkey Public key algorithm - * @v key Key - * @v key_len Key length - * @v ciphertext Ciphertext - * @v ciphertext_len Ciphertext length - * @v expected Expected plaintext - * @v expected_len Expected plaintext length - */ -#define pubkey_decrypt_ok( pubkey, key, key_len, ciphertext, \ - ciphertext_len, expected, expected_len ) do {\ - uint8_t ctx[ (pubkey)->ctxsize ]; \ - \ - ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 ); \ - { \ - size_t max_len = pubkey_max_len ( (pubkey), ctx ); \ - uint8_t decrypted[ max_len ]; \ - int decrypted_len; \ - \ - decrypted_len = pubkey_decrypt ( (pubkey), ctx, \ - (ciphertext), \ - (ciphertext_len), \ - decrypted ); \ - ok ( decrypted_len == ( ( int ) (expected_len) ) ); \ - ok ( memcmp ( decrypted, (expected), \ - (expected_len) ) == 0 ); \ - } \ - pubkey_final ( (pubkey), ctx ); \ - } while ( 0 ) +/** A public-key encryption and decryption test */ +struct pubkey_test { + /** Public-key algorithm */ + struct pubkey_algorithm *pubkey; + /** Private key */ + const struct asn1_cursor private; + /** Public key */ + const struct asn1_cursor public; + /** Plaintext */ + const void *plaintext; + /** Length of plaintext */ + size_t plaintext_len; + /** Ciphertext + * + * Note that the encryption process may include some random + * padding, so a given plaintext will encrypt to multiple + * different ciphertexts. + */ + const void *ciphertext; + /** Length of ciphertext */ + size_t ciphertext_len; +}; + +/** A public-key signature test */ +struct pubkey_sign_test { + /** Public-key algorithm */ + struct pubkey_algorithm *pubkey; + /** Private key */ + const struct asn1_cursor private; + /** Public key */ + const struct asn1_cursor public; + /** Plaintext */ + const void *plaintext; + /** Plaintext length */ + size_t plaintext_len; + /** Signature algorithm */ + struct digest_algorithm *digest; + /** Signature */ + const void *signature; + /** Signature length */ + size_t signature_len; +}; + +/** Define inline private key data */ +#define PRIVATE(...) { __VA_ARGS__ } + +/** Define inline public key data */ +#define PUBLIC(...) { __VA_ARGS__ } + +/** Define inline plaintext data */ +#define PLAINTEXT(...) { __VA_ARGS__ } + +/** Define inline ciphertext data */ +#define CIPHERTEXT(...) { __VA_ARGS__ } + +/** Define inline signature data */ +#define SIGNATURE(...) { __VA_ARGS__ } /** - * Report public key encryption and decryption test result + * Define a public-key encryption and decryption test * - * @v pubkey Public key algorithm - * @v encrypt_key Encryption key - * @v encrypt_key_len Encryption key length - * @v decrypt_key Decryption key - * @v decrypt_key_len Decryption key length - * @v plaintext Plaintext - * @v plaintext_len Plaintext length + * @v name Test name + * @v PUBKEY Public-key algorithm + * @v PRIVATE Private key + * @v PUBLIC Public key + * @v PLAINTEXT Plaintext + * @v CIPHERTEXT Ciphertext + * @ret test Encryption and decryption test */ -#define pubkey_encrypt_ok( pubkey, encrypt_key, encrypt_key_len, \ - decrypt_key, decrypt_key_len, plaintext, \ - plaintext_len ) do { \ - uint8_t ctx[ (pubkey)->ctxsize ]; \ - \ - ok ( pubkey_init ( (pubkey), ctx, (encrypt_key), \ - (encrypt_key_len) ) == 0 ); \ - { \ - size_t max_len = pubkey_max_len ( (pubkey), ctx ); \ - uint8_t encrypted[ max_len ]; \ - int encrypted_len; \ - \ - encrypted_len = pubkey_encrypt ( (pubkey), ctx, \ - (plaintext), \ - (plaintext_len), \ - encrypted ); \ - ok ( encrypted_len >= 0 ); \ - pubkey_decrypt_ok ( (pubkey), (decrypt_key), \ - (decrypt_key_len), encrypted, \ - encrypted_len, (plaintext), \ - (plaintext_len) ); \ - } \ - pubkey_final ( (pubkey), ctx ); \ - } while ( 0 ) +#define PUBKEY_TEST( name, PUBKEY, PRIVATE, PUBLIC, PLAINTEXT, \ + CIPHERTEXT ) \ + static const uint8_t name ## _private[] = PRIVATE; \ + static const uint8_t name ## _public[] = PUBLIC; \ + static const uint8_t name ## _plaintext[] = PLAINTEXT; \ + static const uint8_t name ## _ciphertext[] = CIPHERTEXT; \ + static struct pubkey_test name = { \ + .pubkey = PUBKEY, \ + .private = { \ + .data = name ## _private, \ + .len = sizeof ( name ## _private ), \ + }, \ + .public = { \ + .data = name ## _public, \ + .len = sizeof ( name ## _public ), \ + }, \ + .plaintext = name ## _plaintext, \ + .plaintext_len = sizeof ( name ## _plaintext ), \ + .ciphertext = name ## _ciphertext, \ + .ciphertext_len = sizeof ( name ## _ciphertext ), \ + } /** - * Report public key signature test result + * Define a public-key signature test * - * @v pubkey Public key algorithm - * @v key Key - * @v key_len Key length - * @v digest Digest algorithm - * @v plaintext Plaintext - * @v plaintext_len Plaintext length - * @v expected Expected signature - * @v expected_len Expected signature length + * @v name Test name + * @v PUBKEY Public-key algorithm + * @v PRIVATE Private key + * @v PUBLIC Public key + * @v PLAINTEXT Plaintext + * @v DIGEST Digest algorithm + * @v SIGNATURE Signature + * @ret test Signature test */ -#define pubkey_sign_ok( pubkey, key, key_len, digest, plaintext, \ - plaintext_len, expected, expected_len ) do { \ - uint8_t ctx[ (pubkey)->ctxsize ]; \ - uint8_t digestctx[ (digest)->ctxsize ]; \ - uint8_t digestout[ (digest)->digestsize ]; \ - \ - digest_init ( (digest), digestctx ); \ - digest_update ( (digest), digestctx, (plaintext), \ - (plaintext_len) ); \ - digest_final ( (digest), digestctx, digestout ); \ - \ - ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 ); \ - { \ - size_t max_len = pubkey_max_len ( (pubkey), ctx ); \ - uint8_t signature[ max_len ]; \ - int signature_len; \ - \ - signature_len = pubkey_sign ( (pubkey), ctx, (digest), \ - digestout, signature ); \ - ok ( signature_len == ( ( int ) (expected_len) ) ); \ - ok ( memcmp ( signature, (expected), \ - (expected_len) ) == 0 ); \ - } \ - pubkey_final ( (pubkey), ctx ); \ - } while ( 0 ) +#define PUBKEY_SIGN_TEST( name, PUBKEY, PRIVATE, PUBLIC, PLAINTEXT, \ + DIGEST, SIGNATURE ) \ + static const uint8_t name ## _private[] = PRIVATE; \ + static const uint8_t name ## _public[] = PUBLIC; \ + static const uint8_t name ## _plaintext[] = PLAINTEXT; \ + static const uint8_t name ## _signature[] = SIGNATURE; \ + static struct pubkey_sign_test name = { \ + .pubkey = PUBKEY, \ + .private = { \ + .data = name ## _private, \ + .len = sizeof ( name ## _private ), \ + }, \ + .public = { \ + .data = name ## _public, \ + .len = sizeof ( name ## _public ), \ + }, \ + .plaintext = name ## _plaintext, \ + .plaintext_len = sizeof ( name ## _plaintext ), \ + .digest = DIGEST, \ + .signature = name ## _signature, \ + .signature_len = sizeof ( name ## _signature ), \ + } + +extern void pubkey_okx ( struct pubkey_test *test, + const char *file, unsigned int line ); +extern void pubkey_sign_okx ( struct pubkey_sign_test *test, + const char *file, unsigned int line ); /** - * Report public key verification test result + * Report a public key encryption and decryption test result * - * @v pubkey Public key algorithm - * @v key Key - * @v key_len Key length - * @v digest Digest algorithm - * @v plaintext Plaintext - * @v plaintext_len Plaintext length - * @v signature Signature - * @v signature_len Signature length + * @v test Public key encryption and decryption test */ -#define pubkey_verify_ok( pubkey, key, key_len, digest, plaintext, \ - plaintext_len, signature, signature_len ) do {\ - uint8_t ctx[ (pubkey)->ctxsize ]; \ - uint8_t digestctx[ (digest)->ctxsize ]; \ - uint8_t digestout[ (digest)->digestsize ]; \ - \ - digest_init ( (digest), digestctx ); \ - digest_update ( (digest), digestctx, (plaintext), \ - (plaintext_len) ); \ - digest_final ( (digest), digestctx, digestout ); \ - \ - ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 ); \ - ok ( pubkey_verify ( (pubkey), ctx, (digest), digestout, \ - (signature), (signature_len) ) == 0 ); \ - pubkey_final ( (pubkey), ctx ); \ - } while ( 0 ) +#define pubkey_ok( test ) \ + pubkey_okx ( test, __FILE__, __LINE__ ) /** - * Report public key verification test result + * Report a public key signature test result * - * @v pubkey Public key algorithm - * @v key Key - * @v key_len Key length - * @v digest Digest algorithm - * @v plaintext Plaintext - * @v plaintext_len Plaintext length - * @v signature Signature - * @v signature_len Signature length + * @v test Public key signature test */ -#define pubkey_verify_fail_ok( pubkey, key, key_len, digest, plaintext, \ - plaintext_len, signature, \ - signature_len ) do { \ - uint8_t ctx[ (pubkey)->ctxsize ]; \ - uint8_t digestctx[ (digest)->ctxsize ]; \ - uint8_t digestout[ (digest)->digestsize ]; \ - \ - digest_init ( (digest), digestctx ); \ - digest_update ( (digest), digestctx, (plaintext), \ - (plaintext_len) ); \ - digest_final ( (digest), digestctx, digestout ); \ - \ - ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 ); \ - ok ( pubkey_verify ( (pubkey), ctx, (digest), digestout, \ - (signature), (signature_len) ) != 0 ); \ - pubkey_final ( (pubkey), ctx ); \ - } while ( 0 ) +#define pubkey_sign_ok( test ) \ + pubkey_sign_okx ( test, __FILE__, __LINE__ ) #endif /* _PUBKEY_TEST_H */ diff --git a/src/tests/rsa_test.c b/src/tests/rsa_test.c index 46894f6..1316093 100644 --- a/src/tests/rsa_test.c +++ b/src/tests/rsa_test.c @@ -43,171 +43,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/test.h> #include "pubkey_test.h" -/** Define inline private key data */ -#define PRIVATE(...) { __VA_ARGS__ } - -/** Define inline public key data */ -#define PUBLIC(...) { __VA_ARGS__ } - -/** Define inline plaintext data */ -#define PLAINTEXT(...) { __VA_ARGS__ } - -/** Define inline ciphertext data */ -#define CIPHERTEXT(...) { __VA_ARGS__ } - -/** Define inline signature data */ -#define SIGNATURE(...) { __VA_ARGS__ } - -/** An RSA encryption and decryption self-test */ -struct rsa_encrypt_decrypt_test { - /** Private key */ - const void *private; - /** Private key length */ - size_t private_len; - /** Public key */ - const void *public; - /** Public key length */ - size_t public_len; - /** Plaintext */ - const void *plaintext; - /** Plaintext length */ - size_t plaintext_len; - /** Ciphertext - * - * Note that the encryption process includes some random - * padding, so a given plaintext will encrypt to multiple - * different ciphertexts. - */ - const void *ciphertext; - /** Ciphertext length */ - size_t ciphertext_len; -}; - -/** - * Define an RSA encryption and decryption test - * - * @v name Test name - * @v PRIVATE Private key - * @v PUBLIC Public key - * @v PLAINTEXT Plaintext - * @v CIPHERTEXT Ciphertext - * @ret test Encryption and decryption test - */ -#define RSA_ENCRYPT_DECRYPT_TEST( name, PRIVATE, PUBLIC, PLAINTEXT, \ - CIPHERTEXT ) \ - static const uint8_t name ## _private[] = PRIVATE; \ - static const uint8_t name ## _public[] = PUBLIC; \ - static const uint8_t name ## _plaintext[] = PLAINTEXT; \ - static const uint8_t name ## _ciphertext[] = CIPHERTEXT; \ - static struct rsa_encrypt_decrypt_test name = { \ - .private = name ## _private, \ - .private_len = sizeof ( name ## _private ), \ - .public = name ## _public, \ - .public_len = sizeof ( name ## _public ), \ - .plaintext = name ## _plaintext, \ - .plaintext_len = sizeof ( name ## _plaintext ), \ - .ciphertext = name ## _ciphertext, \ - .ciphertext_len = sizeof ( name ## _ciphertext ), \ - } - -/** An RSA signature self-test */ -struct rsa_signature_test { - /** Private key */ - const void *private; - /** Private key length */ - size_t private_len; - /** Public key */ - const void *public; - /** Public key length */ - size_t public_len; - /** Plaintext */ - const void *plaintext; - /** Plaintext length */ - size_t plaintext_len; - /** Signature algorithm */ - struct asn1_algorithm *algorithm; - /** Signature */ - const void *signature; - /** Signature length */ - size_t signature_len; -}; - -/** - * Define an RSA signature test - * - * @v name Test name - * @v PRIVATE Private key - * @v PUBLIC Public key - * @v PLAINTEXT Plaintext - * @v ALGORITHM Signature algorithm - * @v SIGNATURE Signature - * @ret test Signature test - */ -#define RSA_SIGNATURE_TEST( name, PRIVATE, PUBLIC, PLAINTEXT, \ - ALGORITHM, SIGNATURE ) \ - static const uint8_t name ## _private[] = PRIVATE; \ - static const uint8_t name ## _public[] = PUBLIC; \ - static const uint8_t name ## _plaintext[] = PLAINTEXT; \ - static const uint8_t name ## _signature[] = SIGNATURE; \ - static struct rsa_signature_test name = { \ - .private = name ## _private, \ - .private_len = sizeof ( name ## _private ), \ - .public = name ## _public, \ - .public_len = sizeof ( name ## _public ), \ - .plaintext = name ## _plaintext, \ - .plaintext_len = sizeof ( name ## _plaintext ), \ - .algorithm = ALGORITHM, \ - .signature = name ## _signature, \ - .signature_len = sizeof ( name ## _signature ), \ - } - -/** - * Report RSA encryption and decryption test result - * - * @v test RSA encryption and decryption test - */ -#define rsa_encrypt_decrypt_ok( test ) do { \ - pubkey_decrypt_ok ( &rsa_algorithm, (test)->private, \ - (test)->private_len, (test)->ciphertext, \ - (test)->ciphertext_len, (test)->plaintext, \ - (test)->plaintext_len ); \ - pubkey_encrypt_ok ( &rsa_algorithm, (test)->private, \ - (test)->private_len, (test)->public, \ - (test)->public_len, (test)->plaintext, \ - (test)->plaintext_len ); \ - pubkey_encrypt_ok ( &rsa_algorithm, (test)->public, \ - (test)->public_len, (test)->private, \ - (test)->private_len, (test)->plaintext, \ - (test)->plaintext_len ); \ - } while ( 0 ) - - -/** - * Report RSA signature test result - * - * @v test RSA signature test - */ -#define rsa_signature_ok( test ) do { \ - struct digest_algorithm *digest = (test)->algorithm->digest; \ - uint8_t bad_signature[ (test)->signature_len ]; \ - pubkey_sign_ok ( &rsa_algorithm, (test)->private, \ - (test)->private_len, digest, \ - (test)->plaintext, (test)->plaintext_len, \ - (test)->signature, (test)->signature_len ); \ - pubkey_verify_ok ( &rsa_algorithm, (test)->public, \ - (test)->public_len, digest, \ - (test)->plaintext, (test)->plaintext_len, \ - (test)->signature, (test)->signature_len ); \ - memset ( bad_signature, 0, sizeof ( bad_signature ) ); \ - pubkey_verify_fail_ok ( &rsa_algorithm, (test)->public, \ - (test)->public_len, digest, \ - (test)->plaintext, \ - (test)->plaintext_len, bad_signature, \ - sizeof ( bad_signature ) ); \ - } while ( 0 ) - /** "Hello world" encryption and decryption test (traditional PKCS#1 key) */ -RSA_ENCRYPT_DECRYPT_TEST ( hw_test, +PUBKEY_TEST ( hw_test, &rsa_algorithm, PRIVATE ( 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xd2, 0xf1, 0x04, 0x67, 0xf6, 0x2c, 0x96, 0x07, 0xa6, 0xbd, 0x85, 0xac, 0xc1, 0x17, 0x5d, 0xe8, 0xf0, 0x93, 0x94, 0x0c, @@ -261,7 +98,7 @@ RSA_ENCRYPT_DECRYPT_TEST ( hw_test, 0x38, 0x43, 0xf9, 0x41 ) ); /** "Hello world" encryption and decryption test (PKCS#8 key) */ -RSA_ENCRYPT_DECRYPT_TEST ( hw_test_pkcs8, +PUBKEY_TEST ( hw_test_pkcs8, &rsa_algorithm, PRIVATE ( 0x30, 0x82, 0x01, 0x55, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x3f, 0x30, 0x82, 0x01, 0x3b, @@ -318,7 +155,7 @@ RSA_ENCRYPT_DECRYPT_TEST ( hw_test_pkcs8, 0x38, 0x43, 0xf9, 0x41 ) ); /** Random message MD5 signature test */ -RSA_SIGNATURE_TEST ( md5_test, +PUBKEY_SIGN_TEST ( md5_test, &rsa_algorithm, PRIVATE ( 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xf9, 0x3f, 0x78, 0x44, 0xe2, 0x0e, 0x25, 0xf1, 0x0e, 0x94, 0xcd, 0xca, 0x6f, 0x9e, 0xea, 0x6d, 0xdf, 0xcd, 0xa0, 0x7c, @@ -381,7 +218,7 @@ RSA_SIGNATURE_TEST ( md5_test, 0xf2, 0x8d, 0xfc, 0xfc, 0x37, 0xf7, 0xc7, 0x6d, 0x6c, 0xd8, 0x24, 0x0c, 0x6a, 0xec, 0x82, 0x5c, 0x72, 0xf1, 0xfc, 0x05, 0xed, 0x8e, 0xe8, 0xd9, 0x8b, 0x8b, 0x67, 0x02, 0x95 ), - &md5_with_rsa_encryption_algorithm, + &md5_algorithm, SIGNATURE ( 0xdb, 0x56, 0x3d, 0xea, 0xae, 0x81, 0x4b, 0x3b, 0x2e, 0x8e, 0xb8, 0xee, 0x13, 0x61, 0xc6, 0xe7, 0xd7, 0x50, 0xcd, 0x0d, 0x34, 0x3a, 0xfe, 0x9a, 0x8d, 0xf8, 0xfb, 0xd6, 0x7e, 0xbd, @@ -391,7 +228,7 @@ RSA_SIGNATURE_TEST ( md5_test, 0xac, 0x45, 0x00, 0xa8 ) ); /** Random message SHA-1 signature test */ -RSA_SIGNATURE_TEST ( sha1_test, +PUBKEY_SIGN_TEST ( sha1_test, &rsa_algorithm, PRIVATE ( 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xe0, 0x3a, 0x8d, 0x35, 0xe1, 0x92, 0x2f, 0xea, 0x0d, 0x82, 0x60, 0x2e, 0xb6, 0x0b, 0x02, 0xd3, 0xf4, 0x39, 0xfb, 0x06, @@ -454,7 +291,7 @@ RSA_SIGNATURE_TEST ( sha1_test, 0x30, 0x91, 0x1c, 0xaa, 0x6c, 0x24, 0x42, 0x1b, 0x1a, 0xba, 0x30, 0x40, 0x49, 0x83, 0xd9, 0xd7, 0x66, 0x7e, 0x5c, 0x1a, 0x4b, 0x7f, 0xa6, 0x8e, 0x8a, 0xd6, 0x0c, 0x65, 0x75 ), - &sha1_with_rsa_encryption_algorithm, + &sha1_algorithm, SIGNATURE ( 0xa5, 0x5a, 0x8a, 0x67, 0x81, 0x76, 0x7e, 0xad, 0x99, 0x22, 0xf1, 0x47, 0x64, 0xd2, 0xfb, 0x81, 0x45, 0xeb, 0x85, 0x56, 0xf8, 0x7d, 0xb8, 0xec, 0x41, 0x17, 0x84, 0xf7, 0x2b, 0xbb, @@ -464,7 +301,7 @@ RSA_SIGNATURE_TEST ( sha1_test, 0x0e, 0x3d, 0x80, 0x80 ) ); /** Random message SHA-256 signature test */ -RSA_SIGNATURE_TEST ( sha256_test, +PUBKEY_SIGN_TEST ( sha256_test, &rsa_algorithm, PRIVATE ( 0x30, 0x82, 0x01, 0x3a, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xa5, 0xe9, 0xdb, 0xa9, 0x1a, 0x6e, 0xd6, 0x4c, 0x25, 0x50, 0xfe, 0x61, 0x77, 0x08, 0x7a, 0x80, 0x36, 0xcb, 0x88, 0x49, @@ -527,7 +364,7 @@ RSA_SIGNATURE_TEST ( sha256_test, 0x91, 0x71, 0xd6, 0x2d, 0xa1, 0xae, 0x81, 0x0c, 0xed, 0x54, 0x48, 0x79, 0x8a, 0x78, 0x05, 0x74, 0x4d, 0x4f, 0xf0, 0xe0, 0x3c, 0x41, 0x5c, 0x04, 0x0b, 0x68, 0x57, 0xc5, 0xd6 ), - &sha256_with_rsa_encryption_algorithm, + &sha256_algorithm, SIGNATURE ( 0x02, 0x2e, 0xc5, 0x2a, 0x2b, 0x7f, 0xb4, 0x80, 0xca, 0x9d, 0x96, 0x5b, 0xaf, 0x1f, 0x72, 0x5b, 0x6e, 0xf1, 0x69, 0x7f, 0x4d, 0x41, 0xd5, 0x9f, 0x00, 0xdc, 0x47, 0xf4, 0x68, 0x8f, @@ -542,11 +379,11 @@ RSA_SIGNATURE_TEST ( sha256_test, */ static void rsa_test_exec ( void ) { - rsa_encrypt_decrypt_ok ( &hw_test ); - rsa_encrypt_decrypt_ok ( &hw_test_pkcs8 ); - rsa_signature_ok ( &md5_test ); - rsa_signature_ok ( &sha1_test ); - rsa_signature_ok ( &sha256_test ); + pubkey_ok ( &hw_test ); + pubkey_ok ( &hw_test_pkcs8 ); + pubkey_sign_ok ( &md5_test ); + pubkey_sign_ok ( &sha1_test ); + pubkey_sign_ok ( &sha256_test ); } /** RSA self-test */ @@ -554,3 +391,9 @@ struct self_test rsa_test __self_test = { .name = "rsa", .exec = rsa_test_exec, }; + +/* Drag in required ASN.1 OID-identified algorithms */ +REQUIRING_SYMBOL ( rsa_test ); +REQUIRE_OBJECT ( rsa_md5 ); +REQUIRE_OBJECT ( rsa_sha1 ); +REQUIRE_OBJECT ( rsa_sha256 ); diff --git a/src/usr/imgcrypt.c b/src/usr/imgcrypt.c new file mode 100644 index 0000000..1b649f1 --- /dev/null +++ b/src/usr/imgcrypt.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2024 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 <string.h> +#include <syslog.h> +#include <ipxe/image.h> +#include <ipxe/cms.h> +#include <ipxe/privkey.h> +#include <usr/imgcrypt.h> + +/** @file + * + * Image encryption management + * + */ + +/** + * Decrypt image using downloaded envelope + * + * @v image Image to decrypt + * @v envelope Image containing decryption key + * @v name Decrypted image name (or NULL to use default) + * @ret rc Return status code + */ +int imgdecrypt ( struct image *image, struct image *envelope, + const char *name ) { + struct cms_message *cms; + int rc; + + /* Parse envelope */ + if ( ( rc = cms_message ( envelope, &cms ) ) != 0 ) + goto err_parse; + + /* Decrypt image */ + if ( ( rc = cms_decrypt ( cms, image, name, &private_key ) ) != 0 ) + goto err_decrypt; + + /* Drop reference to message */ + cms_put ( cms ); + cms = NULL; + + /* Record decryption */ + syslog ( LOG_NOTICE, "Image \"%s\" decrypted OK\n", image->name ); + + return 0; + + err_decrypt: + cms_put ( cms ); + err_parse: + syslog ( LOG_ERR, "Image \"%s\" decryption failed: %s\n", + image->name, strerror ( rc ) ); + return rc; +} diff --git a/src/usr/imgtrust.c b/src/usr/imgtrust.c index e7c2067..7f7e7ed 100644 --- a/src/usr/imgtrust.c +++ b/src/usr/imgtrust.c @@ -50,34 +50,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ int imgverify ( struct image *image, struct image *signature, const char *name ) { - struct asn1_cursor *data; - struct cms_signature *sig; - struct cms_signer_info *info; + struct cms_message *cms; + struct cms_participant *part; time_t now; - int next; int rc; - /* Mark image as untrusted */ - image_untrust ( image ); - - /* Get raw signature data */ - next = image_asn1 ( signature, 0, &data ); - if ( next < 0 ) { - rc = next; - goto err_asn1; - } - /* Parse signature */ - if ( ( rc = cms_signature ( data->data, data->len, &sig ) ) != 0 ) + if ( ( rc = cms_message ( signature, &cms ) ) != 0 ) goto err_parse; - /* Free raw signature data */ - free ( data ); - data = NULL; - /* Complete all certificate chains */ - list_for_each_entry ( info, &sig->info, list ) { - if ( ( rc = create_validator ( &monojob, info->chain, + list_for_each_entry ( part, &cms->participants, list ) { + if ( ( rc = create_validator ( &monojob, part->chain, NULL ) ) != 0 ) goto err_create_validator; if ( ( rc = monojob_wait ( NULL, 0 ) ) != 0 ) @@ -86,16 +70,14 @@ int imgverify ( struct image *image, struct image *signature, /* Use signature to verify image */ now = time ( NULL ); - if ( ( rc = cms_verify ( sig, image->data, image->len, - name, now, NULL, NULL ) ) != 0 ) + if ( ( rc = cms_verify ( cms, image, name, now, NULL, NULL ) ) != 0 ) goto err_verify; - /* Drop reference to signature */ - cms_put ( sig ); - sig = NULL; + /* Drop reference to message */ + cms_put ( cms ); + cms = NULL; - /* Mark image as trusted */ - image_trust ( image ); + /* Record signature verification */ syslog ( LOG_NOTICE, "Image \"%s\" signature OK\n", image->name ); return 0; @@ -103,10 +85,8 @@ int imgverify ( struct image *image, struct image *signature, err_verify: err_validator_wait: err_create_validator: - cms_put ( sig ); + cms_put ( cms ); err_parse: - free ( data ); - err_asn1: syslog ( LOG_ERR, "Image \"%s\" signature bad: %s\n", image->name, strerror ( rc ) ); return rc; |