---[ Phrack Magazine Volume 8, Issue 52 January 26, 1998, article 15 of 20 -------------------------[ Technical Guide to Digital Certification --------[ Yggdrasil Introduction ~~~~~~~~~~~~ Today's software technology provides not only flexible controls for web pages and complex remote interaction (ActiveX controls, Java applets and Netscape plugins) but also offers the possibility of downloading pieces of code for local execution to extend browsers capabilities. A major issue being the fact that this code cannot be initially distinguished from malicious code (virii/trojans, "man in the middle" attacks, forced downgrade, forgery of electronic documents, etc), disguised as utilities. The point is that end users do not know who published of a piece of software, if the code has been tampered with, and what that software will do, (until they download and execute it). Anyone can create plugins, applets or controls containing this potentially destructive code or even "intelligent" malevolent code, able to communicate covertly with a remote server. Public-key cryptography has produced a number of different implementations to verify the authenticity of software, network objects, documents and data transactions (for example, Electronic Funds Transfer) using Digital IDs. Authenticode Certifications ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Microsoft recently adopted Authenticode technology to sign their ActiveX based software. Any individual or commercial software publisher desiring their code to be "trusted" must apply for and receive a Digital Certificate from an Authenticode Certificate Authority (CA), such as VeriSign. The CA will request proof-of-identity, and other information, only then will they verify the publishers credentials (even employing Dun & Bradstreet rating). After the CA has decided that the publisher meets its policy criteria, it releases a Certificate (the expected cost is about $500 for a year, plus additional costs for hardware storage for commercial developers, up to $12,000). [ God save the next-generation developers. ] A Digital Certificate contains the publishers public-key (and other info) encrypted according to the industry standard X.509 V3 certificate format and PKCS #7 signed data standards. The ITU-T recommendation for X.509 states that: "It would be a serious breach of security if the CA issued a certificate for a user with a public key that had been tampered with." All Certificates have an expiration time, but the CA may revoke them prior to that time if a publisher's private-key or CA's certificate is assumed to be compromised. The CA may (or may NOT) inform the owner of the certificate. Revocation Lists ~~~~~~~~~~~~~~~~ The Revocation Lists, also called "black-lists", are held within entries as attributes of types CertificateRevocationList and AuthorityRevocationList. Their attribute types are defined as follows: certificateRevocationList ATTRIBUTE ::= { WITH SYNTAX CertificateList EQUALITY MATCHING RULE certificateListExactMatch ID id-at-certificateRevocationList } authorityRevocationList ATTRIBUTE ::= { WITH SYNTAX CertificateList EQUALITY MATCHING RULE certificateListExactMatch ID id-at-authorityRevocationList } CertificateList ::= SIGNED { SEQUENCE { version Version OPTIONAL, signature AlgorithmIdentifier, <----+ issuer Name, | thisUpdate UTCTime, | nextUpdate UTCTime OPTIONAL, version 2 revokedCertificates SEQUENCE OF SEQUENCE { only userCertificate CertificateSerialNumber, (extension) revocationDate UTCTime, | crlEntryExtensions Extensions OPTIONAL } OPTIONAL, | crlExtensions [0] Extensions OPTIONAL }} <----+ Implementation of X.509-3 ~~~~~~~~~~~~~~~~~~~~~~~~~ The ITU-T X.509 Directory Specification makes use of a set of cryptographic systems known as asymmetric Public-Key Crypto-Systems (PKCS). This system involves the use of two keys (one secret and one public as used in common public key packages like PGP). Both keys can be used for encoding: the private key to decipher if the public key was used, and vice versa (Xp*Xs = Xs*Xp, where Xp/Xs are the key-encoding/decoding functions). When applied to Digital Signatures, the public key encryption is used to encipher the data to be signed after it's passed through a hash function. Information is signed by appending to it an enciphered summary of the info. The summary is produced by means of a one-way hash function, while the enciphering is carried out using the private key of the signer. For further information about X.509 and certificate types please read the ITU-T Recommendation X.509 ("The Directory: Authentication Framework"). Windows Trust API ~~~~~~~~~~~~~~~~~ To ascertain an objects reliability under Win32, the WinVerifyTrust() API function is used, according to its prototype as follows: HRESULT --------------- Description --------------- WINAPI WinVerifyTrust ( HWND hwnd, <>0 to allow user to assist in trust decision DWORD dwTrustProvider, 0 = provider unknown, 1 = software publisher DWORD dwActionID, specifies what to verify LPVOID ActionData information required by the trust provider ) The HRESULT return code will be TRUST_E_SUBJECT_NOT_TRUSTED if the object is not trusted (according to the specified action in dwActionID). An error code more detailed than this could be provided by the trust provider. Creation of a Digitally Signed message ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PKCS #7 specifies several "types", such as ContentInfo, SignedData and SignerInfo. Version 1.5 of PKCS #7 describes the ContentInfo type as: ContentInfo ::= SEQUENCE { contentType ContentType, content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } ContentType ::= OBJECT IDENTIFIER the content is (or better: MAY be) an octet-stream ASCII string to be passed to the selected digest algorithm (an example is MD2, see RFC-1321). The first step is to encode the ContentInfo field according to PKCS #7. This is the resulting encoded data: == DATA BLOCK #1 == {30 28} 06 09 0x0609: contentType = data 2A 86 48 86 F7 0D 01 07 01 PKCS #7 data-object ID A0 1B [0] EXPLICIT 04 [msg_len] content = OCTET STRING [octet stream representing the ASCII string, msg_len bytes long] <-- value (*) This (*) data is the input stream to the encoding algorithm (MD2 or other): (the identifier of the PKCS #7 data object is {1 2 840 113549 1 7 1}) == DATA BLOCK #2 == {30 20} 30 0C 0x300C: digestAlgorithm 06 08 2A 86 48 86 F7 0D 02 02 algorithm ID = MD2 05 00 parameters = NULL (0x00) 04 [block_len] digest [encoded data (MD2 output)] (the object identifier of the MD2 algorithm is {1 2 840 113549 2 2}) This data is the encoded DigestInfo. It will be encrypted under RSA using the user's private key. According to PKCS #1, RSA encryption has two main steps: an encryption data block is constructed from a padding string and the prefixed message digest; then the encryption block is exponentiated with the user's private key. The encryption block EB is the following 64-octet string: 00 01 block type FF FF FF FF FF FF FF FF FF FF FF FF FF FF padding string FF FF FF FF FF FF FF FF FF FF FF FF FF 00 separator (0x00) [here goes the whole DATA BLOCK #2] data bytes (prf. message digest) Now we need to encode various information: a SignedData value from the inner ContentInfo value, then the encrypted message digest, the issuer and serial number of the user's certificate, the certificate data, the message digest algorithm ID (MD2) and the encryption algorithm ID (PKCS #1 RSA). The encoded SignedData is: == DATA BLOCK #3 == 30 82 02 3D 02 01 01 version = 1 31 [size of inner data block] digestAlgorithms 30 [size] 06 08 2A 86 48 86 F7 0D 02 02 algorithm ID = MD2 05 00 parameters = NULL (0x00) [ContentInfo data] content = inner ContentInfo A0 82 01 [size] certificates [certificate data] user's certificate 31 81 [size] signerInfos 30 81 [size] 02 01 01 version = 1 30 [size] issuerAndSerialNumber [issuer data] issuer 02 04 {12 34 56 78} size (4), serialNumber (12345678) 30 [alg_size] digestAlgorithm 06 08 2A 86 48 86 F7 0D 02 02 algorithm ID = MD2 05 00 parameters = NULL (0x00) 30 [dig_size] digestEncryptionAlgorithm 06 [sz] rsaEncryption (d.E.A.) 2A 86 48 86 F7 0D 01 01 01 05 00 parameters = NULL (0x00) 04 [data_size] encryptedDigest [encrypted digestInfo encoded data block] Finally, a ContentInfo value from this SignedData data block is encoded (once again, using PKCS #7): 30 82 02 [size] 06 09 2A 86 48 86 F7 0D 01 07 02 contentType = signedData A0 82 02 [size] [0] EXPLICIT [here goes the whole DATA BLOCK #3] content = SignedData value (the object identifier of PKCS #7 signedData is {1 2 840 113549 1 7 2}) PKCS Key Example ~~~~~~~~~~~~~~~~ The following is the full hex dump of the above PKCS #7 encoded key. HEX Dump -------------------------------------: ASCII Dump ----: 30 82 02 50 06 09 2A 86 48 86 F7 0D 01 07 02 A0 0..P..*.H....... 82 02 41 30 82 02 3D 02 01 01 31 0E 30 0C 06 08 ..A0..=...1.0... 2A 86 48 86 F7 0D 02 02 05 00 30 28 06 09 2A 86 *.H.......0(..*. 48 86 F7 0D 01 07 01 A0 1B 04 19 41 20 64 65 6D H..........A dem 6F 20 43 6F 6E 74 65 6E 74 49 6E 66 6F 20 73 74 o ContentInfo st 72 69 6E 67 A0 82 01 5E 30 82 01 5A 30 82 01 04 ring...^0..Z0... 02 04 14 00 00 29 30 0D 06 09 2A 86 48 86 F7 0D .....)0...*.H... 01 01 02 05 00 30 2C 31 0B 30 09 06 03 55 04 06 .....0,1.0...U.. 13 02 55 53 31 1D 30 1B 06 03 55 04 0A 13 14 45 ..US1.0...U....E 78 61 6D 70 6C 65 20 4F 72 67 61 6E 69 7A 61 74 xample Organizat 69 6F 6E 30 1E 17 0D 39 32 30 39 30 39 32 32 31 ion0...920909221 38 30 36 5A 17 0D 39 34 30 39 30 39 32 32 31 38 806Z..9409092218 30 35 5A 30 42 31 0B 30 09 06 03 55 04 06 13 02 05Z0B1.0...U.... 55 53 31 1D 30 1B 06 03 55 04 0A 13 14 45 78 61 US1.0...U....Exa 6D 70 6C 65 20 4F 72 67 61 6E 69 7A 61 74 69 6F mple Organizatio 6E 31 14 30 12 06 03 55 04 03 13 0B 41 20 64 65 n1.0...U....A de 6D 6F 20 55 73 65 72 30 5B 30 0D 06 09 2A 86 48 mo User0[0...*.H 86 F7 0D 01 01 01 05 00 03 4A 00 30 47 02 40 0A .........J.0G.@. 66 79 1D C6 98 81 68 DE 7A B7 74 19 BB 7F B0 C0 fy....h.z.t..... 01 C6 27 10 27 00 75 14 29 42 E1 9A 8D 8C 51 D0 ..'.'.u.)B....Q. 53 B3 E3 78 2A 1D E5 DC 5A F4 EB E9 94 68 17 01 S..x*...Z....h.. 14 A1 DF E6 7C DC 9A 9A F5 5D 65 56 20 BB AB 02 ....|....]eV ... 03 01 00 01 30 0D 06 09 2A 86 48 86 F7 0D 01 01 ....0...*.H..... 02 05 00 03 41 00 45 1A A1 E1 AA 77 20 4A 5F CD ....A.E....w J_. F5 76 06 9D 02 F7 32 C2 6F 36 7B 0D 57 8A 6E 64 .v....2.o6{.W.nd F3 9A 91 1F 47 95 DF 09 94 34 05 11 A0 D1 DF 4A ....G....4.....J 20 B2 6A 77 4C CA EF 75 FC 69 2E 54 C2 A1 93 7C .jwL..u.i.T...| 07 11 26 9D 9B 16 31 81 9B 30 81 98 02 01 01 30 ..&...1..0.....0 34 30 2C 31 0B 30 09 06 03 55 04 06 13 02 55 53 40,1.0...U....US 31 1D 30 1B 06 03 55 04 0A 13 14 45 78 61 6D 70 1.0...U....Examp 6C 65 20 4F 72 67 61 6E 69 7A 61 74 69 6F 6E 02 le Organization. 04 14 00 00 29 30 0C 06 08 2A 86 48 86 F7 0D 02 ....)0...*.H.... 02 05 00 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 ...0...*.H...... 05 00 04 40 05 FA 6A 81 2F C7 DF 8B F4 F2 54 25 ...@..j./.....T% 09 E0 3E 84 6E 11 B9 C6 20 BE 20 09 EF B4 40 EF ..>.n... . ...@. BC C6 69 21 69 94 AC 04 F3 41 B5 7D 05 20 2D 42 ..i!i....A.}. -B 8F B2 A2 7B 5C 77 DF D9 B1 5B FC 3D 55 93 53 50 ...{\w...[.=U.SP 34 10 C1 E1 E1 4.... Many other demo (not only ;) keys, tons of related C++ source/libraries for Linux and Win32 and documentation can be found on my web site at this address (case sensitive): http://members.tripod.com/~xception_0x0A28/penumbra.html "That which does not kill us makes us stronger" -- Friedrich Nietzsche ----[ EOF