3 # Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
4 # Written by David Howells (dhowells@redhat.com)
6 # This file is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This file is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this file; if not, write to the Free Software Foundation,
18 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 # Generate validly formatted X.509 certificates filled with mostly random data,
21 # including for the RSA key and signature fields (so it is extremely improbable
22 # that key will be useful and the signature will verify).
24 # If an argument of any sort is passed this will cause random bytes to be
25 # inserted into the ASN.1 structure (whilst keeping the lengths of the wrapping
26 # constructed elements correct).
30 # x509random.pl [-i] >output
34 #print STDERR "SEED: ", srand(), "\n";
36 my $do_inject = ($#ARGV == 0);
45 my $BIT_STRING = 0x03;
46 my $OCTET_STRING = 0x04;
49 my $UTF8String = 0x0c;
53 my $GeneralizedTime = 0x18;
57 return (int(rand(6)) == 0) ?
'' : $_[0];
60 ###############################################################################
64 ###############################################################################
73 } elsif ($len <= 0xff) {
75 } elsif ($len <= 0xffff) {
77 } elsif ($len <= 0xffffff) {
83 $output .= pack("CC", $tag == -1 ?
int(rand(255)) & ~0x20 : $tag, $l);
85 } elsif ($len <= 0xff) {
86 $output .= pack("C", $len);
87 } elsif ($len <= 0xffff) {
88 $output .= pack("n", $len);
89 } elsif ($len <= 0xffffff) {
90 $output .= pack("Cn", $len >> 16, $len & 0xffff);
92 $output .= pack("N", $len);
98 ###############################################################################
100 # Generate random data
102 ###############################################################################
103 sub emit_random_data
($$)
105 my ($minlen, $maxlen) = @_;
108 my $len = $minlen + int(rand($maxlen - $minlen));
112 $output .= "abcdefghijklmnop";
116 $output .= substr("abcdefghijklmnop", 0, $i);
120 ###############################################################################
122 # Generate a primitive containing some random data
124 ###############################################################################
125 sub emit_asn1_prim
(@
)
127 my ($class, $tag, $minlen, $maxlen) = @_;
130 $minlen = 0 if (!$minlen);
131 $maxlen = 255 if (!$maxlen);
132 $content = ($tag == $NULL) ?
'' : emit_random_data
($minlen, $maxlen);
135 return emit_asn1_hdr
($tag, length($content)) . $content;
138 ###############################################################################
140 # Generate an object identifier
142 ###############################################################################
144 commonName
=> pack("CCC", 85, 4, 3),
145 countryName
=> pack("CCC", 85, 4, 6),
146 organizationName
=> pack("CCC", 85, 4, 10),
147 organizationUnitName
=> pack("CCC", 85, 4, 11),
148 rsaEncryption
=> pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1),
149 sha1WithRSAEncryption
=> pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5),
150 authorityKeyIdentifier
=> pack("CCC", 85, 29, 35),
151 subjectKeyIdentifier
=> pack("CCC", 85, 29, 14),
152 basicConstraints
=> pack("CCC", 85, 29, 19)
155 sub emit_asn1_OID
($$$)
157 my ($class, $tag, $oid_name) = @_;
161 if (!exists($OIDs{$oid_name})) {
162 print STDERR
"Unknown OID: $oid_name\n";
166 $oid = $OIDs{$oid_name};
171 return emit_asn1_hdr
($tag, $len) . $oid;
174 ###############################################################################
176 # Generate a UTC time
178 ###############################################################################
179 sub emit_asn1_utctime
($$)
181 my ($class, $tag) = @_;
185 for (my $i = 0; $i < 12; $i++) {
186 $output .= pack("C", int(rand(9)) + 0x30);
190 $len = length($output);
194 return emit_asn1_hdr
($tag, $len) . $output;
197 ###############################################################################
199 # Generate a generalized time
201 ###############################################################################
202 sub emit_asn1_gentime
($$)
204 my ($class, $tag) = @_;
208 for (my $i = 0; $i < 14; $i++) {
209 $output .= pack("C", int(rand(9)) + 0x30);
213 $len = length($output);
217 return emit_asn1_hdr
($tag, $len) . $output;
220 ###############################################################################
222 # Generate a construct
224 ###############################################################################
225 sub emit_asn1_cons
($$$)
227 my ($class, $tag, $content) = @_;
231 if (int(rand(20)) == 0) {
232 $inject = pack("C", int(rand(255)));
236 $tag |= $class | 0x20;
237 return emit_asn1_hdr
($tag, length($content)) . $content . $inject;
240 ###############################################################################
244 ###############################################################################
245 sub emit_x509_AttributeValueAssertion
($@
)
247 my ($type, $min, $max) = @_;
249 $output = emit_asn1_OID
($UNIV, $OBJ_ID, $type); # attributeType
250 $output .= emit_asn1_prim
($UNIV, $UTF8String, $min, $max); # attributeValue
251 return emit_asn1_cons
($UNIV, $SEQUENCE, $output);
254 sub emit_x509_RelativeDistinguishedName
()
257 # Set of AttributeValueAssertion
258 $output = emit_x509_AttributeValueAssertion
("countryName", 2, 2);
259 $output .= emit_x509_AttributeValueAssertion
("organizationName", 3, 10);
260 $output .= emit_x509_AttributeValueAssertion
("organizationUnitName", 3, 10);
261 $output .= emit_x509_AttributeValueAssertion
("commonName", 4, 16);
262 return emit_asn1_cons
($UNIV, $SET, $output);
269 $output = emit_x509_RelativeDistinguishedName
();
270 return emit_asn1_cons
($UNIV, $SEQUENCE, $output);
273 ###############################################################################
275 # Generate some X.509 extensions
277 ###############################################################################
278 sub emit_x509_SubjectKeyIdentifier
()
280 my $content = emit_asn1_prim
($UNIV, $OCTET_STRING, 10, 20);
284 sub emit_x509_AuthorityKeyIdentifier
()
286 my $content = emit_asn1_prim
($CONT, 0, 10, 20);
287 my $wrapper = emit_asn1_cons
($UNIV, $SEQUENCE, $content);
291 sub emit_x509_BasicConstraints
()
293 my $content = emit_asn1_prim
($UNIV, $BIT_STRING, 1, 7);
297 sub emit_x509_Extension
($)
303 if ($ext eq "authorityKeyIdentifier") {
304 $output = emit_asn1_OID
($UNIV, $OBJ_ID, $ext);
305 $value = emit_x509_AuthorityKeyIdentifier
();
306 } elsif ($ext eq "subjectKeyIdentifier") {
307 $output = emit_asn1_OID
($UNIV, $OBJ_ID, $ext);
308 $value = emit_x509_SubjectKeyIdentifier
();
309 } elsif ($ext eq "basicConstraints") {
310 $output = emit_asn1_OID
($UNIV, $OBJ_ID, $ext);
311 $value = emit_x509_BasicConstraints
();
313 $output = emit_asn1_prim
($UNIV, $OBJ_ID, 3, 10);
314 $value = emit_random_data
(10, 20);
317 $output .= maybe emit_asn1_prim
($UNIV, $BOOLEAN, 1, 1); # critical
318 $output .= emit_asn1_hdr
($UNIV | $OCTET_STRING, length($value)) . $value;
320 return emit_asn1_cons
($UNIV, $SEQUENCE, $output);
323 sub emit_x509_Extensions
()
327 # Probably do want a sequence of extensions here
328 $output .= maybe emit_x509_Extension
("authorityKeyIdentifier");
329 $output .= maybe emit_x509_Extension
("subjectKeyIdentifier");
330 $output .= maybe emit_x509_Extension
("basicConstraints");
331 $output .= maybe emit_x509_Extension
("");
332 $output .= maybe emit_x509_Extension
("");
333 $output .= maybe emit_x509_Extension
("");
334 $output .= maybe emit_x509_Extension
("");
336 return emit_asn1_cons
($CONT, 3, emit_asn1_cons
($UNIV, $SEQUENCE, $output));
339 ###############################################################################
341 # Generate an X.509 certificate
343 ###############################################################################
346 # UTCTime or GeneralizedTime
347 if (int(rand(2)) == 0) {
348 return emit_asn1_utctime
($UNIV, $UTCTime);
350 return emit_asn1_gentime
($UNIV, $GeneralizedTime);
354 sub emit_x509_Validity
()
357 $output = emit_x509_Time
(); # notBefore
358 $output .= emit_x509_Time
(); # notAfter
359 return emit_asn1_cons
($UNIV, $SEQUENCE, $output);
362 sub emit_x509_AlgorithmIdentifier
($)
367 #$output = emit_asn1_prim($UNIV, $OBJ_ID); # algorithm
368 $output = emit_asn1_OID
($UNIV, $OBJ_ID, $oid); # algorithm
369 $output .= emit_asn1_prim
($UNIV, $NULL); # parameters
370 return emit_asn1_cons
($UNIV, $SEQUENCE, $output);
373 sub emit_x509_Version
()
375 my $output = emit_asn1_prim
($UNIV, $INTEGER, 0, 3);
376 return emit_asn1_cons
($CONT, 0, $output);
379 sub emit_x509_SubjectPublicKeyInfo
()
382 $output = emit_x509_AlgorithmIdentifier
("rsaEncryption"); # algorithm
383 $output .= emit_asn1_prim
($UNIV, $BIT_STRING); # subjectPublicKey
384 return emit_asn1_cons
($UNIV, $SEQUENCE, $output);
387 sub emit_x509_TBSCertificate
()
391 $output = emit_x509_Version
; # version
392 $output .= emit_asn1_prim
($UNIV, $INTEGER); # serialNumber
393 $output .= emit_x509_AlgorithmIdentifier
("sha1WithRSAEncryption"); # signature
394 $output .= emit_x509_Name
(); # issuer
395 $output .= emit_x509_Validity
(); # validity
396 $output .= emit_x509_Name
(); # subject
397 $output .= emit_x509_SubjectPublicKeyInfo
(); # subjectPublicKeyInfo
398 $output .= maybe emit_asn1_prim
($CONT, 1); # issuerUniqueID
399 $output .= maybe emit_asn1_prim
($CONT, 2); # subjectUniqueID
400 $output .= emit_x509_Extensions
(); # extensions
402 return emit_asn1_cons
($UNIV, $SEQUENCE, $output);
405 sub emit_x509_Certificate
()
409 $output = emit_x509_TBSCertificate
(); # tbsCertificate
410 $output .= emit_x509_AlgorithmIdentifier
("sha1WithRSAEncryption"); # signatureAlgorithm
411 $output .= emit_asn1_prim
($UNIV, $BIT_STRING); # signature
413 return emit_asn1_cons
($UNIV, $SEQUENCE, $output);
416 print emit_x509_Certificate
();