Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
CA.pl384 linesDownload Raw Back to misc
1#!/usr/bin/env perl2# Copyright 2000-2025 The OpenSSL Project Authors. All Rights Reserved.3#4# Licensed under the Apache License 2.0 (the "License").  You may not use5# this file except in compliance with the License.  You can obtain a copy6# in the file LICENSE in the source distribution or at7# https://www.openssl.org/source/license.html8 9#10# Wrapper around the ca to make it easier to use11#12# WARNING: do not edit!13# Generated by Makefile from apps/CA.pl.in14 15use strict;16use warnings;17 18my $verbose = 1;19my @OPENSSL_CMDS = ("req", "ca", "pkcs12", "x509", "verify");20 21my $openssl = $ENV{'OPENSSL'} // "openssl";22$ENV{'OPENSSL'} = $openssl;23my @openssl = split_val($openssl);24 25my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} // "";26my @OPENSSL_CONFIG = split_val($OPENSSL_CONFIG);27 28# Command invocations.29my @REQ = (@openssl, "req", @OPENSSL_CONFIG);30my @CA = (@openssl, "ca", @OPENSSL_CONFIG);31my @VERIFY = (@openssl, "verify");32my @X509 = (@openssl, "x509");33my @PKCS12 = (@openssl, "pkcs12");34 35# Default values for various configuration settings.36my $CATOP = "/usr/ssl";37my $CAKEY = "cakey.pem";38my $CAREQ = "careq.pem";39my $CACERT = "cacert.pem";40my $CACRL = "crl.pem";41my @DAYS = qw(-days 365);42my @CADAYS = qw(-days 1095);	# 3 years43my @EXTENSIONS = qw(-extensions v3_ca);44my @POLICY = qw(-policy policy_anything);45my $NEWKEY = "newkey.pem";46my $NEWREQ = "newreq.pem";47my $NEWCERT = "newcert.pem";48my $NEWP12 = "newcert.p12";49 50# Commandline parsing51my %EXTRA;52my $WHAT = shift @ARGV // "";53@ARGV = parse_extra(@ARGV);54my $RET = 0;55 56sub split_val {57    return split_val_win32(@_) if ($^O eq 'MSWin32');58    my ($val) = @_;59    my (@ret, @frag);60 61    # Skip leading whitespace62    $val =~ m{\A[ \t]*}ogc;63 64    # Unix shell-compatible split65    #66    # Handles backslash escapes outside quotes and67    # in double-quoted strings.  Parameter and68    # command-substitution is silently ignored.69    # Bare newlines outside quotes and (trailing) backslashes are disallowed.70 71    while (1) {72        last if (pos($val) == length($val));73 74        # The first char is never a SPACE or TAB.  Possible matches are:75        # 1. Ordinary string fragment76        # 2. Single-quoted string77        # 3. Double-quoted string78        # 4. Backslash escape79        # 5. Bare backlash or newline (rejected)80        #81        if ($val =~ m{\G([^'" \t\n\\]+)}ogc) {82            # Ordinary string83            push @frag, $1;84        } elsif ($val =~ m{\G'([^']*)'}ogc) {85            # Single-quoted string86            push @frag, $1;87        } elsif ($val =~ m{\G"}ogc) {88            # Double-quoted string89            push @frag, "";90            while (1) {91                last if ($val =~ m{\G"}ogc);92                if ($val =~ m{\G([^"\\]+)}ogcs) {93                    # literals94                    push @frag, $1;95                } elsif ($val =~ m{\G.(["\`\$\\])}ogc) {96                    # backslash-escaped special97                    push @frag, $1;98                } elsif ($val =~ m{\G.(.)}ogcs) {99                    # backslashed non-special100                    push @frag, "\\$1" unless $1 eq "\n";101                } else {102                    die sprintf("Malformed quoted string: %s\n", $val);103                }104            }105        } elsif ($val =~ m{\G\\(.)}ogc) {106            # Backslash is unconditional escape outside quoted strings107            push @frag, $1 unless $1 eq "\n";108        } else {109            die sprintf("Bare backslash or newline in: '%s'\n", $val);110        }111        # Done if at SPACE, TAB or end, otherwise continue current fragment112        #113        next unless ($val =~ m{\G(?:[ \t]+|\z)}ogcs);114        push @ret, join("", splice(@frag)) if (@frag > 0);115    }116    # Handle final fragment117    push @ret, join("", splice(@frag)) if (@frag > 0);118    return @ret;119}120 121sub split_val_win32 {122    my ($val) = @_;123    my (@ret, @frag);124 125    # Skip leading whitespace126    $val =~ m{\A[ \t]*}ogc;127 128    # Windows-compatible split129    # See: "Parsing C++ command-line arguments" in:130    # https://learn.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=msvc-170131    #132    # Backslashes are special only when followed by a double-quote133    # Pairs of double-quotes make a single double-quote.134    # Closing double-quotes may be omitted.135 136    while (1) {137        last if (pos($val) == length($val));138 139        # The first char is never a SPACE or TAB.140        # 1. Ordinary string fragment141        # 2. Double-quoted string142        # 3. Backslashes preceding a double-quote143        # 4. Literal backslashes144        # 5. Bare newline (rejected)145        #146        if ($val =~ m{\G([^" \t\n\\]+)}ogc) {147            # Ordinary string148            push @frag, $1;149        } elsif ($val =~ m{\G"}ogc) {150            # Double-quoted string151            push @frag, "";152            while (1) {153                if ($val =~ m{\G("+)}ogc) {154                    # Two double-quotes make one literal double-quote155                    my $l = length($1);156                    push @frag, q{"} x int($l/2) if ($l > 1);157                    next if ($l % 2 == 0);158                    last;159                }160                if ($val =~ m{\G([^"\\]+)}ogc) {161                    push @frag, $1;162                } elsif ($val =~ m{\G((?>[\\]+))(?=")}ogc) {163                    # Backslashes before a double-quote are escapes164                    my $l = length($1);165                    push @frag, q{\\} x int($l / 2);166                    if ($l % 2 == 1) {167                        ++pos($val);168                        push @frag, q{"};169                    }170                } elsif ($val =~ m{\G((?:(?>[\\]+)[^"\\]+)+)}ogc) {171                    # Backslashes not before a double-quote are not special172                    push @frag, $1;173                } else {174                    # Tolerate missing closing double-quote175                    last;176                }177            }178        } elsif ($val =~ m{\G((?>[\\]+))(?=")}ogc) {179            my $l = length($1);180            push @frag, q{\\} x int($l / 2);181            if ($l % 2 == 1) {182                ++pos($val);183                push @frag, q{"};184            }185        } elsif ($val =~ m{\G([\\]+)}ogc) {186            # Backslashes not before a double-quote are not special187            push @frag, $1;188        } else {189            die sprintf("Bare newline in: '%s'\n", $val);190        }191        # Done if at SPACE, TAB or end, otherwise continue current fragment192        #193        next unless ($val =~ m{\G(?:[ \t]+|\z)}ogcs);194        push @ret, join("", splice(@frag)) if (@frag > 0);195    }196    # Handle final fragment197    push @ret, join("", splice(@frag)) if (@frag);198    return @ret;199}200 201# Split out "-extra-CMD value", and return new |@ARGV|. Fill in202# |EXTRA{CMD}| with list of values.203sub parse_extra204{205    my @args;206    foreach ( @OPENSSL_CMDS ) {207        $EXTRA{$_} = [];208    }209    while (@_) {210        my $arg = shift(@_);211        if ( $arg !~ m{^-extra-(\w+)$} ) {212            push @args, split_val($arg);213            next;214        }215        $arg = $1;216        die "Unknown \"-extra-${arg}\" option, exiting\n"217            unless grep { $arg eq $_ } @OPENSSL_CMDS;218        die "Missing \"-extra-${arg}\" option value, exiting\n"219            unless (@_ > 0);220        push @{$EXTRA{$arg}}, split_val(shift(@_));221    }222    return @args;223}224 225 226# See if reason for a CRL entry is valid; exit if not.227sub crl_reason_ok228{229    my $r = shift;230 231    if ($r eq 'unspecified' || $r eq 'keyCompromise'232        || $r eq 'CACompromise' || $r eq 'affiliationChanged'233        || $r eq 'superseded' || $r eq 'cessationOfOperation'234        || $r eq 'certificateHold' || $r eq 'removeFromCRL') {235        return 1;236    }237    print STDERR "Invalid CRL reason; must be one of:\n";238    print STDERR "    unspecified, keyCompromise, CACompromise,\n";239    print STDERR "    affiliationChanged, superseded, cessationOfOperation\n";240    print STDERR "    certificateHold, removeFromCRL";241    exit 1;242}243 244# Copy a PEM-format file; return like exit status (zero means ok)245sub copy_pemfile246{247    my ($infile, $outfile, $bound) = @_;248    my $found = 0;249 250    open IN, $infile || die "Cannot open $infile, $!";251    open OUT, ">$outfile" || die "Cannot write to $outfile, $!";252    while (<IN>) {253        $found = 1 if /^-----BEGIN.*$bound/;254        print OUT $_ if $found;255        $found = 2, last if /^-----END.*$bound/;256    }257    close IN;258    close OUT;259    return $found == 2 ? 0 : 1;260}261 262# Wrapper around system; useful for debugging.  Returns just the exit status263sub run264{265    my ($cmd, @args) = @_;266    print "====\n$cmd @args\n" if $verbose;267    my $status = system {$cmd} $cmd, @args;268    print "==> $status\n====\n" if $verbose;269    return $status >> 8;270}271 272 273if ( $WHAT =~ /^(-\?|-h|-help)$/ ) {274    print STDERR <<EOF;275Usage:276    CA.pl -newcert | -newreq | -newreq-nodes | -xsign | -sign | -signCA | -signcert | -crl | -newca [-extra-cmd parameter]277    CA.pl -pkcs12 [certname]278    CA.pl -verify certfile ...279    CA.pl -revoke certfile [reason]280EOF281    exit 0;282}283 284if ($WHAT eq '-newcert' ) {285    # create a certificate286    $RET = run(@REQ, qw(-new -x509 -keyout), $NEWKEY, "-out", $NEWCERT, @DAYS, @{$EXTRA{req}});287    print "Cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0;288} elsif ($WHAT eq '-precert' ) {289    # create a pre-certificate290    $RET = run(@REQ, qw(-x509 -precert -keyout), $NEWKEY, "-out", $NEWCERT, @DAYS, @{$EXTRA{req}});291    print "Pre-cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0;292} elsif ($WHAT =~ /^\-newreq(\-nodes)?$/ ) {293    # create a certificate request294    $RET = run(@REQ, "-new", (defined $1 ? ($1,) : ()), "-keyout", $NEWKEY, "-out", $NEWREQ, @{$EXTRA{req}});295    print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0;296} elsif ($WHAT eq '-newca' ) {297    # create the directory hierarchy298    my @dirs = ( "${CATOP}", "${CATOP}/certs", "${CATOP}/crl",299                "${CATOP}/newcerts", "${CATOP}/private" );300    die "${CATOP}/index.txt exists.\nRemove old sub-tree to proceed,"301        if -f "${CATOP}/index.txt";302    die "${CATOP}/serial exists.\nRemove old sub-tree to proceed,"303        if -f "${CATOP}/serial";304    foreach my $d ( @dirs ) {305        if ( -d $d ) {306            warn "Directory $d exists" if -d $d;307        } else {308            mkdir $d or die "Can't mkdir $d, $!";309        }310    }311 312    open OUT, ">${CATOP}/index.txt";313    close OUT;314    open OUT, ">${CATOP}/crlnumber";315    print OUT "01\n";316    close OUT;317    # ask user for existing CA certificate318    print "CA certificate filename (or enter to create)\n";319    my $FILE;320    $FILE = "" unless defined($FILE = <STDIN>);321    $FILE =~ s{\R$}{};322    if ($FILE ne "") {323        copy_pemfile($FILE,"${CATOP}/private/$CAKEY", "PRIVATE");324        copy_pemfile($FILE,"${CATOP}/$CACERT", "CERTIFICATE");325    } else {326        print "Making CA certificate ...\n";327        $RET = run(@REQ, qw(-new -keyout), "${CATOP}/private/$CAKEY",328                   "-out", "${CATOP}/$CAREQ", @{$EXTRA{req}});329        $RET = run(@CA, qw(-create_serial -out), "${CATOP}/$CACERT", @CADAYS,330                   qw(-batch -keyfile), "${CATOP}/private/$CAKEY", "-selfsign",331                   @EXTENSIONS, "-infiles", "${CATOP}/$CAREQ", @{$EXTRA{ca}})332            if $RET == 0;333        print "CA certificate is in ${CATOP}/$CACERT\n" if $RET == 0;334    }335} elsif ($WHAT eq '-pkcs12' ) {336    my $cname = $ARGV[0];337    $cname = "My Certificate" unless defined $cname;338    $RET = run(@PKCS12, "-in", $NEWCERT, "-inkey", $NEWKEY,339               "-certfile", "${CATOP}/$CACERT", "-out", $NEWP12,340               qw(-export -name), $cname, @{$EXTRA{pkcs12}});341    print "PKCS#12 file is in $NEWP12\n" if $RET == 0;342} elsif ($WHAT eq '-xsign' ) {343    $RET = run(@CA, @POLICY, "-infiles", $NEWREQ, @{$EXTRA{ca}});344} elsif ($WHAT eq '-sign' ) {345    $RET = run(@CA, @POLICY, "-out", $NEWCERT,346               "-infiles", $NEWREQ, @{$EXTRA{ca}});347    print "Signed certificate is in $NEWCERT\n" if $RET == 0;348} elsif ($WHAT eq '-signCA' ) {349    $RET = run(@CA, @POLICY, "-out", $NEWCERT, @EXTENSIONS,350               "-infiles", $NEWREQ, @{$EXTRA{ca}});351    print "Signed CA certificate is in $NEWCERT\n" if $RET == 0;352} elsif ($WHAT eq '-signcert' ) {353    $RET = run(@X509, qw(-x509toreq -in), $NEWREQ, "-signkey", $NEWREQ,354               qw(-out tmp.pem), @{$EXTRA{x509}});355    $RET = run(@CA, @POLICY, "-out", $NEWCERT,356               qw(-infiles tmp.pem), @{$EXTRA{ca}}) if $RET == 0;357    print "Signed certificate is in $NEWCERT\n" if $RET == 0;358} elsif ($WHAT eq '-verify' ) {359    my @files = @ARGV ? @ARGV : ( $NEWCERT );360    foreach my $file (@files) {361        my $status = run(@VERIFY, "-CAfile", "${CATOP}/$CACERT", $file, @{$EXTRA{verify}});362        $RET = $status if $status != 0;363    }364} elsif ($WHAT eq '-crl' ) {365    $RET = run(@CA, qw(-gencrl -out), "${CATOP}/crl/$CACRL", @{$EXTRA{ca}});366    print "Generated CRL is in ${CATOP}/crl/$CACRL\n" if $RET == 0;367} elsif ($WHAT eq '-revoke' ) {368    my $cname = $ARGV[0];369    if (!defined $cname) {370        print "Certificate filename is required; reason optional.\n";371        exit 1;372    }373    my @reason;374    @reason = ("-crl_reason", $ARGV[1])375        if defined $ARGV[1] && crl_reason_ok($ARGV[1]);376    $RET = run(@CA, "-revoke", $cname, @reason, @{$EXTRA{ca}});377} else {378    print STDERR "Unknown arg \"$WHAT\"\n";379    print STDERR "Use -help for help.\n";380    exit 1;381}382 383exit $RET;384 
codekingpro/portable-devtools · Team Ai