diff --git a/__tests__/fixtures/signatures/pinning/leaf-only.json b/__tests__/fixtures/signatures/pinning/leaf-only.json new file mode 100644 index 0000000..6cbafb2 --- /dev/null +++ b/__tests__/fixtures/signatures/pinning/leaf-only.json @@ -0,0 +1,26 @@ +{ + "mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.2", + "verificationMaterial": { + "x509CertificateChain": { + "certificates": [ + { + "rawBytes": "MIIEIzCCAgugAwIBAgIUOp6v9e+JrE5OXdi9j1cyJ5kq8J4wDQYJKoZIhvcNAQENBQAwfDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMREwDwYDVQQKEwhDb2luYmFzZTERMA8GA1UECxMIU2VjdXJpdHkxIjAgBgNVBAMTGWNvcnBvcmF0ZS5kZXZpY2UuY2JocS5uZXQwHhcNMjYwMTIzMjMwNDE0WhcNMjYwMTI0MjMwNDE0WjBZMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xETAPBgNVBAoTCENvaW5iYXNlMRIwEAYDVQQLEwljb3Jwb3JhdGUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQ6uQBengAJg0GjKT6wWD1gVRY+hIcQC12KSUD+vii3RvxxXVn/wZVviNrFOHfVm6RMFm/OtwuzuLQ18y7i9zIhtaFylQ4/6aXpZ9Nf6yrUdHd91UFq1D973Kz7niWqA/+jbjBsMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSMEGDAWgBQyvkU1R2wkcPgcZOqxRSxnjCP8ezAkBgNVHREEHTAbhhlsZGFwOi8vL2Jhc2UtZmFjaWxpdGF0b3JzMA0GCSqGSIb3DQEBDQUAA4ICAQBVXpfTFpCttCeaKu1elrVFGzjXgKh/b5de2cW0X+b498ZZVrSWKzb0ZL7zfP9ZNXXFV64sy7ijo9zNMBmdErdl8HwDw3GYyfWedzrvwwvgHrDveRghd3bmwd08vaU6jpUwzhrq30a1SLao3TgkaHpvnZvEpdtKv7cRwadz0bUUTHKjdQTosL7MCS2jupCQ1HSqxWvZ490tbTiTAFyUQUJvlDcv0AsUMAUdUD6TWgPrDWZ4AS8W00vsAlZCrobv3UVHImGsJgVQmDHQ83gMYLGGFgPSQ3iON0koFz0KqJtAbYv3RU3A3faQ90T2KI9A3e1AwETjQwbvVN722NyIEPjzdOtbcpUMrCaZkuWs3sB9tJO3PWLnAqKFSyd6CYOwxHDb/aZyxN5BPtBBz9BxdnM42T7KjABUQ1pINMHHoXZYGjQvH+9C3kygOrgvo04iFKgZwhS+rKphZVllUpkzxv7yfG5QqOVUM0o45LcGVgYJfX/istXT3VCff/I2xgSw+McAzTIlYK539C8oNpbXefym0XXbPlXmOVe3oKC0UwcxdNthIS0ptinnKl0jJ8JKDJRphbk6hZb1f+ak1v3w8Ftj8/CoBGEF5o51kD7TlelgaPWXZMedJfrk8XUoqfZLYa7CmOzif0XHKHzTz5pKcJQ75/Hod+SzCqyVghvV8hjJfg==" + } + ] + }, + "timestampVerificationData": { + "rfc3161Timestamps": [ + { + "signedTimestamp": "MIICyTADAgEAMIICwAYJKoZIhvcNAQcCoIICsTCCAq0CAQMxDTALBglghkgBZQMEAgEwgbcGCyqGSIb3DQEJEAEEoIGnBIGkMIGhAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQguXTXv6cm2iEjF2nneUhNQ9Um8zCPcxKYvQJnjnJljaYCFHj03SNBghQNLyvPlUlgz7iOhb6/GA8yMDI2MDEyMzIzMDQxNVowAwIBAaAypDAwLjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MRUwEwYDVQQDEwxzaWdzdG9yZS10c2GgADGCAdswggHXAgEBMFEwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZAIUOhNULwyQYe68wUMvy4qOiyojiwwwCwYJYIZIAWUDBAIBoIH8MBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYwMTIzMjMwNDE1WjAvBgkqhkiG9w0BCQQxIgQgOiTt85EwxNC4CVLW0S8vLJSgw7W4BiUIsFg4UcEaBMcwgY4GCyqGSIb3DQEJEAIvMX8wfTB7MHkEIIX5J7wHq2LKw7RDVsEO/IGyxog/2nq55thw2dE6zQW3MFUwPaQ7MDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQCFDoTVC8MkGHuvMFDL8uKjosqI4sMMAoGCCqGSM49BAMCBGcwZQIwYkJP6elkSXKrIbF+QXk7ipJQBrwi9NJstYfdvsBGI0iVRRJH1IjQmx13iiVd23EcAjEAuV+0VTZW4WO16ZWW+j+Z0rlBOcLVKb29ALdLylgMo0r8SHWKRGPNMFZUT8IfDHYo" + } + ] + } + }, + "messageSignature": { + "messageDigest": { + "algorithm": "SHA2_384", + "digest": "0BfGnSK3SvSkB04GcrW/My7qDhoWCV52qR1VNCGZFWjfIFA+H/jETdHvdTzKOIh5" + }, + "signature": "MGYCMQDrKHTGPwG2Fp7fd1fTQjxZKn+/cBEcfvhOoGns80CoPG6xIH1MlMqLuWE62Tr8P58CMQCq9mETXWy77dkr02jove5BW0k2DF6lFgeKJoTmKWtj7p8ug6qTiDfszo/UluVu0RA=" + } +} diff --git a/__tests__/fixtures/signatures/pinning/missing-root.json b/__tests__/fixtures/signatures/pinning/missing-root.json new file mode 100644 index 0000000..7dfe9e4 --- /dev/null +++ b/__tests__/fixtures/signatures/pinning/missing-root.json @@ -0,0 +1,32 @@ +{ + "mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.2", + "verificationMaterial": { + "x509CertificateChain": { + "certificates": [ + { + "rawBytes": "MIIEIzCCAgugAwIBAgIUOp6v9e+JrE5OXdi9j1cyJ5kq8J4wDQYJKoZIhvcNAQENBQAwfDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMREwDwYDVQQKEwhDb2luYmFzZTERMA8GA1UECxMIU2VjdXJpdHkxIjAgBgNVBAMTGWNvcnBvcmF0ZS5kZXZpY2UuY2JocS5uZXQwHhcNMjYwMTIzMjMwNDE0WhcNMjYwMTI0MjMwNDE0WjBZMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xETAPBgNVBAoTCENvaW5iYXNlMRIwEAYDVQQLEwljb3Jwb3JhdGUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQ6uQBengAJg0GjKT6wWD1gVRY+hIcQC12KSUD+vii3RvxxXVn/wZVviNrFOHfVm6RMFm/OtwuzuLQ18y7i9zIhtaFylQ4/6aXpZ9Nf6yrUdHd91UFq1D973Kz7niWqA/+jbjBsMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSMEGDAWgBQyvkU1R2wkcPgcZOqxRSxnjCP8ezAkBgNVHREEHTAbhhlsZGFwOi8vL2Jhc2UtZmFjaWxpdGF0b3JzMA0GCSqGSIb3DQEBDQUAA4ICAQBVXpfTFpCttCeaKu1elrVFGzjXgKh/b5de2cW0X+b498ZZVrSWKzb0ZL7zfP9ZNXXFV64sy7ijo9zNMBmdErdl8HwDw3GYyfWedzrvwwvgHrDveRghd3bmwd08vaU6jpUwzhrq30a1SLao3TgkaHpvnZvEpdtKv7cRwadz0bUUTHKjdQTosL7MCS2jupCQ1HSqxWvZ490tbTiTAFyUQUJvlDcv0AsUMAUdUD6TWgPrDWZ4AS8W00vsAlZCrobv3UVHImGsJgVQmDHQ83gMYLGGFgPSQ3iON0koFz0KqJtAbYv3RU3A3faQ90T2KI9A3e1AwETjQwbvVN722NyIEPjzdOtbcpUMrCaZkuWs3sB9tJO3PWLnAqKFSyd6CYOwxHDb/aZyxN5BPtBBz9BxdnM42T7KjABUQ1pINMHHoXZYGjQvH+9C3kygOrgvo04iFKgZwhS+rKphZVllUpkzxv7yfG5QqOVUM0o45LcGVgYJfX/istXT3VCff/I2xgSw+McAzTIlYK539C8oNpbXefym0XXbPlXmOVe3oKC0UwcxdNthIS0ptinnKl0jJ8JKDJRphbk6hZb1f+ak1v3w8Ftj8/CoBGEF5o51kD7TlelgaPWXZMedJfrk8XUoqfZLYa7CmOzif0XHKHzTz5pKcJQ75/Hod+SzCqyVghvV8hjJfg==" + }, + { + "rawBytes": "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" + }, + { + "rawBytes": "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" + } + ] + }, + "timestampVerificationData": { + "rfc3161Timestamps": [ + { + "signedTimestamp": "MIICyTADAgEAMIICwAYJKoZIhvcNAQcCoIICsTCCAq0CAQMxDTALBglghkgBZQMEAgEwgbcGCyqGSIb3DQEJEAEEoIGnBIGkMIGhAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQguXTXv6cm2iEjF2nneUhNQ9Um8zCPcxKYvQJnjnJljaYCFHj03SNBghQNLyvPlUlgz7iOhb6/GA8yMDI2MDEyMzIzMDQxNVowAwIBAaAypDAwLjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MRUwEwYDVQQDEwxzaWdzdG9yZS10c2GgADGCAdswggHXAgEBMFEwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZAIUOhNULwyQYe68wUMvy4qOiyojiwwwCwYJYIZIAWUDBAIBoIH8MBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYwMTIzMjMwNDE1WjAvBgkqhkiG9w0BCQQxIgQgOiTt85EwxNC4CVLW0S8vLJSgw7W4BiUIsFg4UcEaBMcwgY4GCyqGSIb3DQEJEAIvMX8wfTB7MHkEIIX5J7wHq2LKw7RDVsEO/IGyxog/2nq55thw2dE6zQW3MFUwPaQ7MDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQCFDoTVC8MkGHuvMFDL8uKjosqI4sMMAoGCCqGSM49BAMCBGcwZQIwYkJP6elkSXKrIbF+QXk7ipJQBrwi9NJstYfdvsBGI0iVRRJH1IjQmx13iiVd23EcAjEAuV+0VTZW4WO16ZWW+j+Z0rlBOcLVKb29ALdLylgMo0r8SHWKRGPNMFZUT8IfDHYo" + } + ] + } + }, + "messageSignature": { + "messageDigest": { + "algorithm": "SHA2_384", + "digest": "0BfGnSK3SvSkB04GcrW/My7qDhoWCV52qR1VNCGZFWjfIFA+H/jETdHvdTzKOIh5" + }, + "signature": "MGYCMQDrKHTGPwG2Fp7fd1fTQjxZKn+/cBEcfvhOoGns80CoPG6xIH1MlMqLuWE62Tr8P58CMQCq9mETXWy77dkr02jove5BW0k2DF6lFgeKJoTmKWtj7p8ug6qTiDfszo/UluVu0RA=" + } +} diff --git a/__tests__/fixtures/signatures/pinning/self-signed-chain.json b/__tests__/fixtures/signatures/pinning/self-signed-chain.json new file mode 100644 index 0000000..325e0fd --- /dev/null +++ b/__tests__/fixtures/signatures/pinning/self-signed-chain.json @@ -0,0 +1,35 @@ +{ + "mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.2", + "verificationMaterial": { + "x509CertificateChain": { + "certificates": [ + { + "rawBytes": "MIIC9TCCAd2gAwIBAgIBAzANBgkqhkiG9w0BAQsFADAkMSIwIAYDVQQDExljb3Jwb3JhdGUuZGV2aWNlLmNiaHEubmV0MCAXDTIwMDEwMTAwMDAwMFoYDzIwNTAwMTAxMDAwMDAwWjARMQ8wDQYDVQQDEwZmb3JnZWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDF7en1otICjtDRcIZjXZB8QLaLi2gwpeEdBrwgrC6N+voWsyzh7z6r8NE40CSQbwxMLxHTKkpDDm8WYgvJShNee7FPaRUw997fb5apty9vGsddOsap3iAK++RGiuxO6ludhjK1+/ZRiYlajMdg/YnC1j95J/AHG06rY/9b3dvVqtrR3kXAhf9w7qj2zEQwGLhYd+o0b56d5JkJQIPKoaXu1eS4Pf2ydkdxHh4Nes0GmD9ClEyGnBEfDYqojsnDxW3Gsv42EDjJuNdTTQ3XeAU2SthTi5OQ8/SNQV1WXXb5+3Skcmj2ox1hcHB/b4mNYqqeAq/sBHqu5hs5EZLxnrKDAgMBAAGjQzBBMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMCQGA1UdEQQdMBuGGWxkYXA6Ly8vYmFzZS1mYWNpbGl0YXRvcnMwDQYJKoZIhvcNAQELBQADggEBAC4/lj9MCIo/686Z8abht61kSarRECiU3Lq4wqHcGsCDL+KAQJHPrQrAVrOykiAlUih1dWgJ+LAhzHMXABvLPXKzeCgypa8cUdixnyM5sTjO6yFKgNUQzRnaEHEZdAFtdjPs4YqQ2Sz13Lj3eoneguH5XoX/dKd/T5Oa16yQTcG0/WSvLNqNvRXTM2Sbh0YYno24FD4ecdKfroaEdlSShG8+l27WfYlAj1NL2/4U0z54Myppvn2oPh+ARrGAjr/cyzncts+1yDIK3VIAuZtnKt8A76/6ITzKP6BZzKEz9Eh6b1W6ebLaF6aBVv4Xvu2s2mjHt9yko0ax08XpclLN0gY=" + }, + { + "rawBytes": "MIIC2zCCAcOgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDEwxDQi1ST09ULUNPUkUwIBcNMjAwMTAxMDAwMDAwWhgPMjA1MDAxMDEwMDAwMDBaMCQxIjAgBgNVBAMTGWNvcnBvcmF0ZS5kZXZpY2UuY2JocS5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAxpnrKtP6F3xr5BbcQ0wYcuFvdbQ3BA31g72pkEiHtlHSqu3sQKAzgX4yAmwcjohdMoCQVCUlznWxG8MjHu52Kgc5Upie/LggoPEi7eqkptNnSL56aecU8PCXvJEZkxFa+bbeMdSh6Dga+0t5LdCRx9XDd5ulmvDHIIfaaymLamsFRu2GIlFwJyJ612navqN/ip1pAay5SbFgDZQ7cujAu3Hk4sUAwYYO01T1L2Wt4Uic1sLHgcGTDgivbexZu5G2iraT7Uxr1DQJ3L6CzH7hdkc+lLMfUmgeIJsaCpgjM0Na0snV4BuFhZ3iIFlB7rsUc6uuyDtXiuzYU5/DDA2JAgMBAAGjIzAhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQB/k9qjFNKkPkraukz+5CtQVce4B2zNYjLfoTh023Jb0hc4UZ9R4dW+qAYq8lf/jSDxrfAXuBKyB3k7yleMgIkeCfjAzrwhwtA85x2KyRdr4s8UYk11ZMu578CF2CBIzTyIz9nk9BkCEt75B7XbDzN0gi6wN9k2JmjZJzbLyySYPKuA0it5cwV5iur8A5jXQx/VFr0PVCwDe82wRneWGvn2mV/JRBhDn5eNDdaSHJ0NW2lbDaL+Nl+6PMD1sFp4p0/GpupGTJ5asuy3EfUkYMMouUC79Sy4fN4A2I4MRmnsFMsabccWQMlAnu3oyBHtgeNwTHgHNmN7lRDqyh3szQPv" + }, + { + "rawBytes": "MIIC2zCCAcOgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDEwxDQi1ST09ULUNPUkUwIBcNMjAwMTAxMDAwMDAwWhgPMjA1MDAxMDEwMDAwMDBaMCQxIjAgBgNVBAMTGWNvcnBvcmF0ZS5kZXZpY2UuY2JocS5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAxpnrKtP6F3xr5BbcQ0wYcuFvdbQ3BA31g72pkEiHtlHSqu3sQKAzgX4yAmwcjohdMoCQVCUlznWxG8MjHu52Kgc5Upie/LggoPEi7eqkptNnSL56aecU8PCXvJEZkxFa+bbeMdSh6Dga+0t5LdCRx9XDd5ulmvDHIIfaaymLamsFRu2GIlFwJyJ612navqN/ip1pAay5SbFgDZQ7cujAu3Hk4sUAwYYO01T1L2Wt4Uic1sLHgcGTDgivbexZu5G2iraT7Uxr1DQJ3L6CzH7hdkc+lLMfUmgeIJsaCpgjM0Na0snV4BuFhZ3iIFlB7rsUc6uuyDtXiuzYU5/DDA2JAgMBAAGjIzAhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQB/k9qjFNKkPkraukz+5CtQVce4B2zNYjLfoTh023Jb0hc4UZ9R4dW+qAYq8lf/jSDxrfAXuBKyB3k7yleMgIkeCfjAzrwhwtA85x2KyRdr4s8UYk11ZMu578CF2CBIzTyIz9nk9BkCEt75B7XbDzN0gi6wN9k2JmjZJzbLyySYPKuA0it5cwV5iur8A5jXQx/VFr0PVCwDe82wRneWGvn2mV/JRBhDn5eNDdaSHJ0NW2lbDaL+Nl+6PMD1sFp4p0/GpupGTJ5asuy3EfUkYMMouUC79Sy4fN4A2I4MRmnsFMsabccWQMlAnu3oyBHtgeNwTHgHNmN7lRDqyh3szQPv" + }, + { + "rawBytes": "MIICzjCCAbagAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDEwxDQi1ST09ULUNPUkUwIBcNMjAwMTAxMDAwMDAwWhgPMjA1MDAxMDEwMDAwMDBaMBcxFTATBgNVBAMTDENCLVJPT1QtQ09SRTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8PpIjTe3OqCW6r6GvJnDggkxffDSFYGgScVPZCh0XKR1Au5YRiMqvoJykQ4AfZMmcV7mIBkiRyNO/9hNRR6F3Uo4/Krgr6EPMXsyAxOdmX5BvdsxfA324N35rlHuP1+sPdzz1mA+SrEFD1CIdEKZsYyA7LYnbwxrYRcOjUGCbvIlIAYpmqU28u3nPFe7GyR2f7wuqW1Tu25MCbG1KBnfUFgLh4tWOOsP6tneBflUY7eoa1BnRuuSl1oQ+pm+G5l3xwzV9cylZ1gvLtY1KOV93gtMpjpsaDQE68t21CW6+dpfbfoxXqE0HvM2L07Ss5quFzVoaSzu0HYoz6PqmX0LsCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBADfStzgs7zaPgzE1amytWTA5U+vPw3BxLYrkuvVtKSTye20QngkuKHuDA/POwRUXQTUXr6sLtZreRg2HJOm4JF8sB0qZJB1UkGo1+fSFFSat6BWaNDGENxgSIAzjTgOK3lucpVUthsPMAGyWtDe4TCCOS/1mcSn7Nv4iBwHVoeD9f1IKxrcxwj4kbTAg9LmoeJpNnkF/j1czHWX92FZNHUIBPEXca9OfpzWLTcz9+bTisnRgi1dYXpF88hIGRPDZlzn3i4yddsP31cVC+inID6VQ+6B7yrKzDAuFQg+x2k0jUYZjaCnOhLUBYm9qrMPaKbEL0HcfKU0K/Qq9NcqsvDQ=" + } + ] + }, + "timestampVerificationData": { + "rfc3161Timestamps": [ + { + "signedTimestamp": "MIICyTADAgEAMIICwAYJKoZIhvcNAQcCoIICsTCCAq0CAQMxDTALBglghkgBZQMEAgEwgbcGCyqGSIb3DQEJEAEEoIGnBIGkMIGhAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQguXTXv6cm2iEjF2nneUhNQ9Um8zCPcxKYvQJnjnJljaYCFHj03SNBghQNLyvPlUlgz7iOhb6/GA8yMDI2MDEyMzIzMDQxNVowAwIBAaAypDAwLjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MRUwEwYDVQQDEwxzaWdzdG9yZS10c2GgADGCAdswggHXAgEBMFEwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZAIUOhNULwyQYe68wUMvy4qOiyojiwwwCwYJYIZIAWUDBAIBoIH8MBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYwMTIzMjMwNDE1WjAvBgkqhkiG9w0BCQQxIgQgOiTt85EwxNC4CVLW0S8vLJSgw7W4BiUIsFg4UcEaBMcwgY4GCyqGSIb3DQEJEAIvMX8wfTB7MHkEIIX5J7wHq2LKw7RDVsEO/IGyxog/2nq55thw2dE6zQW3MFUwPaQ7MDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQCFDoTVC8MkGHuvMFDL8uKjosqI4sMMAoGCCqGSM49BAMCBGcwZQIwYkJP6elkSXKrIbF+QXk7ipJQBrwi9NJstYfdvsBGI0iVRRJH1IjQmx13iiVd23EcAjEAuV+0VTZW4WO16ZWW+j+Z0rlBOcLVKb29ALdLylgMo0r8SHWKRGPNMFZUT8IfDHYo" + } + ] + } + }, + "messageSignature": { + "messageDigest": { + "algorithm": "SHA2_384", + "digest": "0BfGnSK3SvSkB04GcrW/My7qDhoWCV52qR1VNCGZFWjfIFA+H/jETdHvdTzKOIh5" + }, + "signature": "MGYCMQDrKHTGPwG2Fp7fd1fTQjxZKn+/cBEcfvhOoGns80CoPG6xIH1MlMqLuWE62Tr8P58CMQCq9mETXWy77dkr02jove5BW0k2DF6lFgeKJoTmKWtj7p8ug6qTiDfszo/UluVu0RA=" + } +} diff --git a/__tests__/task-origin-validate.test.ts b/__tests__/task-origin-validate.test.ts index dde6ba7..e15d8b8 100644 --- a/__tests__/task-origin-validate.test.ts +++ b/__tests__/task-origin-validate.test.ts @@ -19,6 +19,7 @@ const FIXTURES_DIR = path.resolve(__dirname, 'fixtures'); const VALID_TASK_FOLDER = path.join(FIXTURES_DIR, 'valid-task', 'config', 'chain1'); const MODIFIED_TASK_FOLDER = path.join(FIXTURES_DIR, 'modified-task', 'config', 'chain1'); const VALID_SIGNATURES_DIR = path.join(FIXTURES_DIR, 'signatures/valid'); +const PINNING_SIGNATURES_DIR = path.join(FIXTURES_DIR, 'signatures/pinning'); // Task creator email const TASK_CREATOR_EMAIL = 'alexis.williams.1@coinbase.com'; @@ -249,4 +250,43 @@ describe('buildAndValidateSignature', () => { ).rejects.toThrow(); }); }); + + describe('certificate chain pinning', () => { + it('rejects a bundle whose certificate chain is fully self-signed', async () => { + // The pins refuse to inject the self-minted root/intermediate as trust anchors, + // so no trusted certificate path can be built for the forged leaf. + await expect( + buildAndValidateSignature({ + taskFolderPath: VALID_TASK_FOLDER, + signatureFile: path.join(PINNING_SIGNATURES_DIR, 'self-signed-chain.json'), + commonName: 'base-facilitators', + role: 'baseFacilitator' as TaskOriginRole, + }) + ).rejects.toThrow(/certificate chain/i); + }); + + it('rejects a bundle missing the root certificate', async () => { + // [leaf, runtime, static] with the root ([3]) dropped. + await expect( + buildAndValidateSignature({ + taskFolderPath: VALID_TASK_FOLDER, + signatureFile: path.join(PINNING_SIGNATURES_DIR, 'missing-root.json'), + commonName: 'base-facilitators', + role: 'baseFacilitator' as TaskOriginRole, + }) + ).rejects.toThrow('certificate chain must contain a runtime intermediate and root'); + }); + + it('rejects a bundle with only a leaf certificate', async () => { + // Only [leaf] present, so both the runtime intermediate ([1]) and root ([3]) are missing. + await expect( + buildAndValidateSignature({ + taskFolderPath: VALID_TASK_FOLDER, + signatureFile: path.join(PINNING_SIGNATURES_DIR, 'leaf-only.json'), + commonName: 'base-facilitators', + role: 'baseFacilitator' as TaskOriginRole, + }) + ).rejects.toThrow('certificate chain must contain a runtime intermediate and root'); + }); + }); }); diff --git a/src/lib/task-origin-validate.ts b/src/lib/task-origin-validate.ts index 811ba62..7103e77 100644 --- a/src/lib/task-origin-validate.ts +++ b/src/lib/task-origin-validate.ts @@ -1,6 +1,7 @@ import * as tar from 'tar'; import path from 'path'; import fs from 'fs/promises'; +import { X509Certificate } from 'crypto'; import { Verifier, toTrustMaterial, toSignedEntity } from '@sigstore/verify'; import { bundleFromJSON } from '@sigstore/bundle'; import trustedRoot from './config/trusted-root.json'; @@ -135,6 +136,14 @@ export async function buildAndValidateSignature(options: TaskOriginVerifyOptions const runtimeIntermediate = bundleCerts[1] ? { rawBytes: bundleCerts[1].rawBytes } : null; const rootCert = bundleCerts[3] ? { rawBytes: bundleCerts[3].rawBytes } : null; + // The pinning below assumes the bundle carries the full cert chain. Fails early if this + // assumption is not met. + if (!runtimeIntermediate || !rootCert) { + throw new Error( + 'Invalid signature bundle: certificate chain must contain a runtime intermediate and root' + ); + } + // Prepare trust material with: // 1. Date strings converted to Date objects (required for filtering) // 2. Runtime intermediate CA injected into certificate chain @@ -150,10 +159,19 @@ export async function buildAndValidateSignature(options: TaskOriginVerifyOptions rawBytes: Buffer.from(cert.rawBytes, 'base64'), })); - // Build the certificate chain: base certs + runtime intermediate + root + // Build the certificate chain: base certs + runtime intermediate + root. + const staticInter = new X509Certificate(baseCerts[0].rawBytes); const certChain = [...baseCerts]; - if (runtimeIntermediate) certChain.push(runtimeIntermediate); - if (rootCert) certChain.push(rootCert); + + // Only inject bundle CAs if they verify against the pinned static intermediate. + const root = new X509Certificate(new Uint8Array(rootCert.rawBytes)); + if (root.ca && staticInter.verify(root.publicKey)) { + const runtime = new X509Certificate(new Uint8Array(runtimeIntermediate.rawBytes)); + if (runtime.ca && runtime.verify(staticInter.publicKey)) { + certChain.push(runtimeIntermediate); + certChain.push(rootCert); + } + } // eslint-disable-next-line @typescript-eslint/no-explicit-any const normalized: any = {