using System; using System.Text; using System.IO; using CryptoSysPKI; namespace MpegOfCat { /* * This demonstrates the feature in CryptoSys PKI v12 to add an arbitrary X.509 Extension to a version 3 X.509 certificate. * As an extreme example, we add a video of a cat. This was done originally by Dave Smith of New Zealand back in 1998. * We've used a cut-down video of Dave playing with his cat. It's an mp4 file instead of an mpeg file, to make it smaller, * but you'll get the idea. * How useful is this? Well, not at all. The original example by Dave Smith was to demonstrate that you could legally put any * old rubbish in an X.509 certificate, even a video of you playing with your cat. * You can, of course, use this feature to add proper Extensions to an X.509 certificate not otherwise supported with the * standard options in CryptoSys PKI. You need a good understanding of ASN.1 DER encoding to do this. * * The video is added as an Extension of type "subjectAltName" (2 5 29 17) with a GeneralName using CHOICE [0] AnotherName, * which takes any value with tag [0]. In this case, the type-id is mpeg-1 and the value is the contents * of the mpeg file as an implicit OCTET STRING with tag [0]. * In this example, note the mp4 signature "ftypmp42" (hex: 66 74 79 70 6D 70 34 32) at offset 4. * If you extract and save the 215388 bytes starting 00 00 00 18 66 74 79 70 6D 70 34 32 ..., you have the mp4 file. */ /* * extnValue (to be encapsulated in an OCTET STRING) 000000 34978: SEQUENCE { 000005 34973: . [0] { 00000A B: . . OBJECT IDENTIFIER mpeg-1 (1 3 6 1 4 1 3029 42 11172 1) 000017 34961: . . [0] { 00001C 3495C: . . . OCTET STRING : . . . . 00 00 00 18 66 74 79 70 6D 70 34 32 00 00 00 00 : . . . . 69 73 6F 6D 6D 70 34 32 00 00 03 E5 6D 6F 6F 76 : . . . . 00 00 00 6C 6D 76 68 64 00 00 00 00 D6 E1 D3 C6 : . . . . D6 E1 D3 C6 00 01 5F 90 00 03 4B C0 00 01 00 00 : . . . . 01 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 : . . . . 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 : . . . . 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 : . . . . 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : . . . . . . . . [ Another 215260 bytes skipped ] : . . . } : . . } : . } */ /* Using Asn1.TextDump() 30 83 03 49 78 --SEQUENCE/215416=0x34978 a0 83 03 49 73 --[0]/215411=0x34973 06 0b --OBJECTIDENTIFIER/11=0xB 2b 06 01 04 01 97 55 2a d7 24 01 --mpeg-1 (1.3.6.1.4.1.3029.42.11172.1) a0 83 03 49 61 --[0]/215393=0x34961 04 83 03 49 5c --OCTETSTRING/215388=0x3495C 00 00 00 18 66 74 79 70 6d 70 34 32 00 00 00 00 69 73 6f 6d 6d 70 34 32 00 00 03 e5 6d 6f 6f 76 -----[cut]----- 83 d8 c5 96 b4 16 29 ee 01 6c db f2 94 96 f5 4b 6d 4f f7 79 87 13 f0 00 00 00 01 0a --(215421 bytes) */ class MpegOfCat { static void Main(string[] args) { string vidfile = "x509cat.mp4"; string certfile = "cat.cer"; // Compose DER-encoded ASN.1 value in hex. In effect, by hand. // We'll cheat here and assume the ASN.1 length bytes are always of the form 83 xx xx xx, // so we are expecting a video file of size 65536 to 16777215 bytes (0x010000 - 0xFFFFFF) // Our template in hex (white space will be removed later) string template = @"30 83 www a0 83 xxx 06 0b 2b 06 01 04 01 97 55 2a d7 24 01 a0 83 yyy 04 83 zzz "; // where "zzz" = length of video file in hex (3 bytes) // "yyy" = zzz + 5 // "xxx" = zzz + 23 // "www" = zzz + 28 Console.WriteLine("PKI Version = {0}", General.Version()); // Read in video file as array of bytes byte[] vidarr = File.ReadAllBytes(vidfile); int vidlen = vidarr.Length; Console.WriteLine("FILE: {0}: {1} bytes", vidfile, vidlen); // Compose lengths as 3-byte big-endian values hex encoded string zzz = NumToHex3(vidlen); Console.WriteLine("zzz={0}", zzz); string yyy = NumToHex3(vidlen + 5); Console.WriteLine("yyy={0}", yyy); string xxx = NumToHex3(vidlen + 23); Console.WriteLine("xxx={0}", xxx); string www = NumToHex3(vidlen + 28); Console.WriteLine("www={0}", www); // Substitute hex-encoded value in template and strip spaces string asn1hex = template.Replace("www", www).Replace("xxx", xxx).Replace("yyy", yyy).Replace("zzz", zzz); Console.WriteLine("ASN.1:\n{0}", asn1hex); asn1hex = asn1hex.Replace(" ", "").Replace("\r", "").Replace("\n", ""); Console.WriteLine(asn1hex); // Append video bytes in hex asn1hex = asn1hex + Cnv.ToHex(vidarr); // Compose Extension string of form <dotted-oid>=#<hexstring> (don't forget the hash symbol '#') string extns = "2.5.29.17=#" + asn1hex; // Create X509 certificate, signed by Carl, using Alice's public key int r = X509.MakeCert(certfile, "CarlRSASelf.cer", "AlicePubRSA.pub", "CarlPrivRSASign.p8e", 0x1001, 4, "CN=Alice;OU=Feline", extns, X509.KeyUsageOptions.DigitalSignature, "password", 0); if (0 == r) { Console.WriteLine("Created certificate '{0}'", certfile); } else { Console.WriteLine("ERROR: {0}: {1}", General.ErrorLookup(r), General.LastError()); } } /// <summary> /// Compose hex encoding of integer n represented by exactly 3 bytes. /// </summary> /// <param name="n">Integer n to be encoded.</param> /// <returns>Hex encoding of exactly 6 hex digits, n mod 0xFFFFFF.</returns> static string NumToHex3(int n) { uint z = (uint)n; byte[] zz = Cnv.NumToBytes(z, Cnv.EndianNess.BigEndian); string zzz = Cnv.ToHex(zz).Substring(2); return zzz; } } }