#!/usr/bin/perl

#
# Copyright 2022 International Business Machines Corp.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

#
# Generate openssl.cnf from the system config file with added engine section
# for ibmca engine.
#
# USE WITH CARE: No automation can replace human knowledge and understanding
#                of the desired configuration!
#

use strict;
use warnings;

sub generate()
{
    my ($osslconfpath);
    my ($tmp, $ih, $line, $oh, $defaultcnfsect, $indefaultsect, $enginesect);

    $osslconfpath = `openssl version -d` || die "Please install openssl binary";
    $osslconfpath =~ s/OPENSSLDIR: \"([^\"]*)\"$/$1/ || die "Failed to extract OpenSSL configuration directory";
    chomp $osslconfpath;

    open($ih, "<", "$osslconfpath/openssl.cnf") or die "Cannot open $osslconfpath/openssl.cnf";
    open($oh, ">", "openssl.cnf.ibmca") or die "Cannot open openssl.cnf.ibmca";

    $defaultcnfsect = undef;
    $indefaultsect = 0;
    $enginesect = undef;
    while ($line = <$ih>) {
        if ($line =~ /openssl_conf\s*=\s*(.*)/) {
            $defaultcnfsect = $1;
            chomp $defaultcnfsect;
        }
        if ($indefaultsect) {
            if ($line =~ /\[\s*\w+\s*\]/) {
                if (!$enginesect) {
                    print $oh "engines = engine_section\n"
                }
                $indefaultsect = 0;
            } elsif ($line =~ /^\s*engines\s*=\s*(\w+)\s*/) {
                $enginesect = $1;
                chomp $enginesect;
            }
        }
        print $oh "$line";
        if ($defaultcnfsect && $line =~ /\[\s*$defaultcnfsect\s*\]/) {
            $indefaultsect = 1;
        }
        if ($enginesect && $line =~ /\[\s*$enginesect\s*\]/) {
            print $oh "ibmca = ibmca_section\n"
        }
    }
    if (!$defaultcnfsect) {
        print $oh, qq|
openssl_conf = openssl_init

[openssl_init]
engines = engine_section
|;
    }
    if (!$enginesect) {
        print $oh qq|
[engine_section]
ibmca = ibmca_section
|;
    }
    print $oh qq|
[ibmca_section]
# The openssl engine path for ibmca.so.
# Set the dynamic_path to where the ibmca.so engine
# resides on the system.
dynamic_path = /usr/lib64/engines-3/ibmca.so
engine_id = ibmca
init = 1

#
# The following ibmca algorithms will be enabled by these parameters
# to the default_algorithms line. Any combination of these is valid,
# with "ALL" denoting the same as all of them in a comma separated
# list.
#
# Note: Algorithms denoted by CIPHERS, DIGESTS, EC (since IBM z15 for certain
# curves), and PKEY are already accelerated by OpenSSL itself using CPACF.
# Therefore, do not accelerate them using the IBMCA engine. This would actually
# make them slower.
#
# Moreover, ibmca's CIPHER and DIGEST implementations do not
# support the processing of messages in arbitrary chunk sizes.
# All chunks, except the final one, are required to be a multiple
# of the primitive's block size.
#
# RSA
# - RSA encrypt, decrypt, sign and verify, key lengths 512-4096
#
# DH
# - DH key exchange
#
# DSA
# - DSA sign and verify
#
# RAND
# - Hardware random number generation
#
# ECDSA (OpenSSL < 1.1.0)
# - Elliptic Curve DSA sign and verify
#
# ECDH (OpenSSL < 1.1.0)
# - Elliptic Curve DH key exchange
#
# EC (OpenSSL >= 1.1.0)
# - Elliptic Curve DSA sign and verify, Elliptic Curve DH key exchange
#
# CIPHERS
# - DES-ECB, DES-CBC, DES-CFB, DES-OFB,
#   DES-EDE3, DES-EDE3-CBC, DES-EDE3-CFB, DES-EDE3-OFB,
#   AES-128-ECB, AES-128-CBC, AES-128-CFB, AES-128-OFB, id-aes128-GCM,
#   AES-192-ECB, AES-192-CBC, AES-192-CFB, AES-192-OFB, id-aes192-GCM,
#   AES-256-ECB, AES-256-CBC, AES-256-CFB, AES-256-OFB, id-aes256-GCM ciphers
#
# DIGESTS
# - SHA1, SHA256, SHA512 digests
#
# PKEY_CRYPTO
# - X25519, X448, ED25519, ED448

default_algorithms = RSA,DH,DSA,RAND
|;
    close($ih);
    close($oh);
    print qq|
Successfully generated openssl.cnf.ibmca file.  Please review this configuration
and, if you are happy with the changes, replace $osslconfpath/openssl.cnf with
this file.
|;
}

print "WARNING: The OpenSSL engine feature is DEPRECATED since OpenSSL 3.0.\n";
print "WARNING: It will be removed in the future.\n";
print "WARNING: Please use the OpenSSL provider instead.\n";

generate();
