updated copyright
[gnutls.git] / tests / suite / x509random.pl
blob1c6ce04eeb62043bb75bebe58ef5aafaf2e6fcab
1 #!/usr/bin/perl -w
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).
28 # Format:
30 # x509random.pl [-i] >output
32 use strict;
34 #print STDERR "SEED: ", srand(), "\n";
36 my $do_inject = ($#ARGV == 0);
38 my $UNIV = 0 << 6;
39 my $APPL = 1 << 6;
40 my $CONT = 2 << 6;
41 my $PRIV = 3 << 6;
43 my $BOOLEAN = 0x01;
44 my $INTEGER = 0x02;
45 my $BIT_STRING = 0x03;
46 my $OCTET_STRING = 0x04;
47 my $NULL = 0x05;
48 my $OBJ_ID = 0x06;
49 my $UTF8String = 0x0c;
50 my $SEQUENCE = 0x10;
51 my $SET = 0x11;
52 my $UTCTime = 0x17;
53 my $GeneralizedTime = 0x18;
55 sub maybe($)
57 return (int(rand(6)) == 0) ? '' : $_[0];
60 ###############################################################################
62 # Generate a header
64 ###############################################################################
65 sub emit_asn1_hdr($$)
67 my ($tag, $len) = @_;
68 my $output = "";
69 my $l;
71 if ($len < 0x80) {
72 $l = $len;
73 } elsif ($len <= 0xff) {
74 $l = 0x81;
75 } elsif ($len <= 0xffff) {
76 $l = 0x82;
77 } elsif ($len <= 0xffffff) {
78 $l = 0x83;
79 } else {
80 $l = 0x84;
83 $output .= pack("CC", $tag == -1 ? int(rand(255)) & ~0x20 : $tag, $l);
84 if ($len < 0x80) {
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);
91 } else {
92 $output .= pack("N", $len);
95 return $output;
98 ###############################################################################
100 # Generate random data
102 ###############################################################################
103 sub emit_random_data($$)
105 my ($minlen, $maxlen) = @_;
106 my $output = '';
108 my $len = $minlen + int(rand($maxlen - $minlen));
110 my $i = $len;
111 while ($i > 16) {
112 $output .= "abcdefghijklmnop";
113 $i -= 16;
116 $output .= substr("abcdefghijklmnop", 0, $i);
117 return $output;
120 ###############################################################################
122 # Generate a primitive containing some random data
124 ###############################################################################
125 sub emit_asn1_prim(@)
127 my ($class, $tag, $minlen, $maxlen) = @_;
128 my $content;
130 $minlen = 0 if (!$minlen);
131 $maxlen = 255 if (!$maxlen);
132 $content = ($tag == $NULL) ? '' : emit_random_data($minlen, $maxlen);
134 $tag |= $class;
135 return emit_asn1_hdr($tag, length($content)) . $content;
138 ###############################################################################
140 # Generate an object identifier
142 ###############################################################################
143 my %OIDs = (
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) = @_;
158 my $oid;
159 my $len;
161 if (!exists($OIDs{$oid_name})) {
162 print STDERR "Unknown OID: $oid_name\n";
163 exit(2);
166 $oid = $OIDs{$oid_name};
167 $len = length($oid);
169 $tag |= $class;
171 return emit_asn1_hdr($tag, $len) . $oid;
174 ###############################################################################
176 # Generate a UTC time
178 ###############################################################################
179 sub emit_asn1_utctime($$)
181 my ($class, $tag) = @_;
182 my $output = "";
183 my $len;
185 for (my $i = 0; $i < 12; $i++) {
186 $output .= pack("C", int(rand(9)) + 0x30);
188 $output .= 'Z';
190 $len = length($output);
192 $tag |= $class;
194 return emit_asn1_hdr($tag, $len) . $output;
197 ###############################################################################
199 # Generate a generalized time
201 ###############################################################################
202 sub emit_asn1_gentime($$)
204 my ($class, $tag) = @_;
205 my $output = "";
206 my $len;
208 for (my $i = 0; $i < 14; $i++) {
209 $output .= pack("C", int(rand(9)) + 0x30);
211 $output .= 'Z';
213 $len = length($output);
215 $tag |= $class;
217 return emit_asn1_hdr($tag, $len) . $output;
220 ###############################################################################
222 # Generate a construct
224 ###############################################################################
225 sub emit_asn1_cons($$$)
227 my ($class, $tag, $content) = @_;
228 my $inject = '';
230 if ($do_inject) {
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 ###############################################################################
242 # Generate a name
244 ###############################################################################
245 sub emit_x509_AttributeValueAssertion($@)
247 my ($type, $min, $max) = @_;
248 my $output;
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()
256 my $output;
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);
265 sub emit_x509_Name()
267 my $output;
268 # Sequence of RDN
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);
281 return $content;
284 sub emit_x509_AuthorityKeyIdentifier()
286 my $content = emit_asn1_prim($CONT, 0, 10, 20);
287 my $wrapper = emit_asn1_cons($UNIV, $SEQUENCE, $content);
288 return $wrapper;
291 sub emit_x509_BasicConstraints()
293 my $content = emit_asn1_prim($UNIV, $BIT_STRING, 1, 7);
294 return $content;
297 sub emit_x509_Extension($)
299 my ($ext) = @_;
300 my $output;
301 my $value = "";
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();
312 } else {
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()
325 my $output = "";
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 ###############################################################################
344 sub emit_x509_Time()
346 # UTCTime or GeneralizedTime
347 if (int(rand(2)) == 0) {
348 return emit_asn1_utctime($UNIV, $UTCTime);
349 } else {
350 return emit_asn1_gentime($UNIV, $GeneralizedTime);
354 sub emit_x509_Validity()
356 my $output;
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($)
364 my ($oid) = @_;
365 my $output;
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()
381 my $output;
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()
389 my $output;
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()
407 my $output;
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();