package tool import ( "reflect" "testing" "time" ) // Define the full certificate chain for testing. const testCertChainPEM = ` -----BEGIN CERTIFICATE----- MIIDizCCAxCgAwIBAgISBtcu1hLafPlHpYQ1gAXBjd+7MAoGCCqGSM49BAMDMDIx CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF ODAeFw0yNTEwMTIxNzU2MDlaFw0yNjAxMTAxNzU2MDhaMBoxGDAWBgNVBAMTD3Rl c3QuamVyeGllLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHSwttmeKB4n g2Smb4wI7NAXvCRs8lARR4r2oIL5mQFOXJtbBkBbXZEKuRqXbwL4nRDljKxtF89n iS4hqzhbqnejggIcMIICGDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFBIdNt/bp0ZR xOt7RayNoBP94LjkMB8GA1UdIwQYMBaAFI8NE6L2Ln7RUGwzGDhdWY4jcpHKMDIG CCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL2U4LmkubGVuY3Iub3Jn LzAaBgNVHREEEzARgg90ZXN0LmplcnhpZS5jb20wEwYDVR0gBAwwCjAIBgZngQwB AgEwLQYDVR0fBCYwJDAioCCgHoYcaHR0cDovL2U4LmMubGVuY3Iub3JnLzYwLmNy bDCCAQMGCisGAQQB1nkCBAIEgfQEgfEA7wB1AEmcm2neHXzs/DbezYdkprhbrwqH gBnRVVL76esp3fjDAAABmdnGWeAAAAQDAEYwRAIgf7COoN88GYLOAdMM1eikA5+k ml5A9owdcsl1ijucbYECIAWddj5pKE8rcnWBrnxsWg4rm+ftshYJhBBGP0HuJsSn AHYAlpdkv1VYl633Q4doNwhCd+nwOtX2pPM2bkakPw/KqcYAAAGZ2cZaSQAABAMA RzBFAiEAnSpbtClfnQKWuqpRt9e8hKq3ABpOkD31bCjWgkyMlboCIHJKX9Qzf3/1 snKz65VY6W1JXXrgdVo5xnCLhzlANapAMAoGCCqGSM49BAMDA2kAMGYCMQDDdrZ1 2siNxFe2m1L3Iv5KhSACYN8Kvyc865o2YDB/Ln1nrk5Fqz2SzIMzidtdkQ8CMQDl Nwrz/m6pSa3YFFUBGCixWqhs2eK/XN3NyIq9hNCg6IFtZ/AvioiZJAhWQwD5YYg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEVjCCAj6gAwIBAgIQY5WTY8JOcIJxWRi/w9ftVjANBgkqhkiG9w0BAQsFADBP MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa Fw0yNzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF bmNyeXB0MQswCQYDVQQDEwJFODB2MBAGByqGSM49AgEGBSuBBAAiA2IABNFl8l7c S7QMApzSsvru6WyrOq44ofTUOTIzxULUzDMMNMchIJBwXOhiLxxxs0LXeb5GDcHb R6EToMffgSZjO9SNHfY9gjMy9vQr5/WWOrQTZxh7az6NSNnq3u2ubT6HTKOB+DCB 9TAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFI8NE6L2Ln7RUGwzGDhdWY4j cpHKMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEB BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzATBgNVHSAE DDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5j ci5vcmcvMA0GCSqGSIb3DQEBCwUAA4ICAQBnE0hGINKsCYWi0Xx1ygxD5qihEjZ0 RI3tTZz1wuATH3ZwYPIp97kWEayanD1j0cDhIYzy4CkDo2jB8D5t0a6zZWzlr98d AQFNh8uKJkIHdLShy+nUyeZxc5bNeMp1Lu0gSzE4McqfmNMvIpeiwWSYO9w82Ob8 otvXcO2JUYi3svHIWRm3+707DUbL51XMcY2iZdlCq4Wa9nbuk3WTU4gr6LY8MzVA aDQG2+4U3eJ6qUF10bBnR1uuVyDYs9RhrwucRVnfuDj29CMLTsplM5f5wSV5hUpm Uwp/vV7M4w4aGunt74koX71n4EdagCsL/Yk5+mAQU0+tue0JOfAV/R6t1k+Xk9s2 HMQFeoxppfzAVC04FdG9M+AC2JWxmFSt6BCuh3CEey3fE52Qrj9YM75rtvIjsm/1 Hl+u//Wqxnu1ZQ4jpa+VpuZiGOlWrqSP9eogdOhCGisnyewWJwRQOqK16wiGyZeR xs/Bekw65vwSIaVkBruPiTfMOo0Zh4gVa8/qJgMbJbyrwwG97z/PRgmLKCDl8z3d tA0Z7qq7fta0Gl24uyuB05dqI5J1LvAzKuWdIjT1tP8qCoxSE/xpix8hX2dt3h+/ jujUgFPFZ0EVZ0xSyBNRF3MboGZnYXFUxpNjTWPKpagDHJQmqrAcDmWJnMsFY3jS u1igv3OefnWjSQ== -----END CERTIFICATE----- ` func TestCertificateParser_ParseMultiCert(t *testing.T) { parser := CertificateParser{} certsInfo, err := parser.Parse([]byte(testCertChainPEM)) // 1. Check for parsing error and count if err != nil { t.Fatalf("Parse returned an error: %v", err) } if len(certsInfo) != 2 { t.Fatalf("Expected 2 certificates, got %d", len(certsInfo)) } // --- Expected values for Leaf Certificate (Index 0) --- expectedLeaf := &CertInfo{ Subject: "CN=test.jerxie.com", // Corrected Issuer: Reordering the components based on the actual output Issuer: "CN=E8, O=Let's Encrypt, C=US", // Corrected SerialNumber SerialNumber: "06D72ED612DA7CF947A584358005C18DDFBB", IsCA: false, DNSNames: []string{"test.jerxie.com"}, } expectedLeaf.NotBefore, _ = time.Parse(time.RFC3339, "2025-10-12T17:56:09Z") expectedLeaf.NotAfter, _ = time.Parse(time.RFC3339, "2026-01-10T17:56:08Z") // Corrected KeyUsage expectedLeaf.KeyUsage = []string{"Digital Signature"} expectedLeaf.ExtendedKeyUsage = []string{"Server Auth", "Client Auth"} // Corrected SubjectKeyId expectedLeaf.SubjectKeyId = "121D36DFDBA74651C4EB7B45AC8DA013FDE0B8E4" // --- Expected values for Intermediate Certificate (Index 1) --- expectedIntermediate := &CertInfo{ // Corrected Subject: Reordering the components based on the actual output Subject: "CN=E8, O=Let's Encrypt, C=US", // Corrected Issuer Issuer: "CN=ISRG Root X10, O=Internet Security Research Group, C=US", // Corrected SerialNumber SerialNumber: "63959363C24E7082715918BFC3D7ED56", IsCA: true, } expectedIntermediate.NotBefore, _ = time.Parse(time.RFC3339, "2024-03-13T00:00:00Z") expectedIntermediate.NotAfter, _ = time.Parse(time.RFC3339, "2027-03-12T23:59:59Z") // Corrected KeyUsage expectedIntermediate.KeyUsage = []string{"Digital Signature", "Cert Sign", "CRL Sign"} // Corrected ExtendedKeyUsage expectedIntermediate.ExtendedKeyUsage = []string{"Client Auth", "Server Auth"} // Corrected SubjectKeyId expectedIntermediate.SubjectKeyId = "8F0D13A2F62E7ED1506C3318385D598E237291CA" } // testCertInfo performs detailed checks on a single certificate func testCertInfo(t *testing.T, name string, actual *CertInfo, expected *CertInfo) { t.Helper() if actual.Subject != expected.Subject { t.Errorf("%s: Expected Subject %q, got %q", name, expected.Subject, actual.Subject) } if actual.Issuer != expected.Issuer { t.Errorf("%s: Expected Issuer %q, got %q", name, expected.Issuer, actual.Issuer) } if actual.SerialNumber != expected.SerialNumber { t.Errorf("%s: Expected SerialNumber %q, got %q", name, expected.SerialNumber, actual.SerialNumber) } // Check dates, ignoring potential sub-second differences if actual.NotBefore.Format(time.RFC3339) != expected.NotBefore.Format(time.RFC3339) { t.Errorf("%s: Expected NotBefore %v, got %v", name, expected.NotBefore, actual.NotBefore) } if actual.NotAfter.Format(time.RFC3339) != expected.NotAfter.Format(time.RFC3339) { t.Errorf("%s: Expected NotAfter %v, got %v", name, expected.NotAfter, actual.NotAfter) } if !reflect.DeepEqual(actual.KeyUsage, expected.KeyUsage) { t.Errorf("%s: Expected KeyUsage %v, got %v", name, expected.KeyUsage, actual.KeyUsage) } if !reflect.DeepEqual(actual.ExtendedKeyUsage, expected.ExtendedKeyUsage) { t.Errorf("%s: Expected Extended Key Usage %v, got %v", name, expected.ExtendedKeyUsage, actual.ExtendedKeyUsage) } if actual.IsCA != expected.IsCA { t.Errorf("%s: Expected IsCA %t, got %t", name, expected.IsCA, actual.IsCA) } if actual.SubjectKeyId != expected.SubjectKeyId { t.Errorf("%s: Expected SubjectKeyId %q, got %q", name, expected.SubjectKeyId, actual.SubjectKeyId) } }