Search code examples
phpopensslcertificatedigital-signature

How to extract the signature value from a certificate in PHP


i have a certificate :

-----BEGIN CERTIFICATE-----
MIIEvzCCBGSgAwIBAgITeAAARlJXpwVPUYDkbAABAABGUjAKBggqhkjOPQQDAjBi
MRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxEzARBgoJkiaJk/IsZAEZFgNnb3YxFzAV
BgoJkiaJk/IsZAEZFgdleHRnYXp0MRswGQYDVQQDExJQRVpFSU5WT0lDRVNDQTQt
Q0EwHhcNMjQwNzAyMDMxMTE2WhcNMjYwNzAyMDMyMTE2WjBJMQswCQYDVQQGEwJT
QTESMBAGA1UEChMJZnJlZSB0ZXh0MRIwEAYDVQQLEwlmcmVlIHRleHQxEjAQBgNV
BAMTCWZyZWUgdGV4dDBWMBAGByqGSM49AgEGBSuBBAAKA0IABP/Lh6KN1Y5Z6CzW
+3hLkwGLUyorKQoCCQZzrbtvHNLocvv7OFDUHZZiOnwzhavZLkOEPjH8ojIH1kb1
A4LsTEejggMTMIIDDzB+BgNVHREEdzB1pHMwcTEgMB4GA1UEBAwXMS1TaGFFa3wy
LVNoYUVrfDMtU2hhRWsxHzAdBgoJkiaJk/IsZAEBDA8zMTExOTAyOTM3MDAwMDMx
DTALBgNVBAwMBDExMDAxDjAMBgNVBBoMBWphemFuMQ0wCwYDVQQPDARUZWNoMB0G
A1UdDgQWBBQJ9H6ej6E1lbOuT+RG6WI9yHrdATAfBgNVHSMEGDAWgBTHwOa3qd0S
yk89bWiCliFF8wF1pDCB5QYDVR0fBIHdMIHaMIHXoIHUoIHRhoHObGRhcDovLy9D
Tj1QRVpFSU5WT0lDRVNDQTQtQ0EoMSksQ049UFJaRUlOVk9JQ0VQS0k0LENOPUNE
UCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25m
aWd1cmF0aW9uLERDPWV4dHphdGNhLERDPWdvdixEQz1sb2NhbD9jZXJ0aWZpY2F0
ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9u
UG9pbnQwgc4GCCsGAQUFBwEBBIHBMIG+MIG7BggrBgEFBQcwAoaBrmxkYXA6Ly8v
Q049UEVaRUlOVk9JQ0VTQ0E0LUNBLENOPUFJQSxDTj1QdWJsaWMlMjBLZXklMjBT
ZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPWV4dHphdGNh
LERDPWdvdixEQz1sb2NhbD9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9
Y2VydGlmaWNhdGlvbkF1dGhvcml0eTAOBgNVHQ8BAf8EBAMCB4AwPAYJKwYBBAGC
NxUHBC8wLQYlKwYBBAGCNxUIgYaoHYTQ+xKG7Z0kh877GdPAVWaBnNgtg+XFXQIB
ZAIBEDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwMwJwYJKwYBBAGCNxUK
BBowGDAKBggrBgEFBQcDAjAKBggrBgEFBQcDAzAKBggqhkjOPQQDAgNJADBGAiEA
2sVgVJidhX8lnKshVB4JL7YBY+F1p48JI7NPpO4xJDQCIQCWf97LYNEK7358msfA
RK1iTp3om8fnJ33A59SurRjENA==
-----END CERTIFICATE-----

and i want to get the signature value that is in this certificate.

i tried many solutions and this the closest one to the needed result.


$cert = openssl_x509_read($certificate);

openssl_x509_export($cert, $out, FALSE);

echo $out;

this solution gives me the whole information about the certificate , also the signature with them , but as string :


Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            78:00:00:46:52:57:a7:05:4f:51:80:e4:6c:00:01:00:00:46:52
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: DC=local, DC=gov, DC=extgazt, CN=PEZEINVOICESCA4-CA
        Validity
            Not Before: Jul  2 03:11:16 2024 GMT
            Not After : Jul  2 03:21:16 2026 GMT
        Subject: C=SA, O=free text, OU=free text, CN=free text
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:ff:cb:87:a2:8d:d5:8e:59:e8:2c:d6:fb:78:4b:
                    93:01:8b:53:2a:2b:29:0a:02:09:06:73:ad:bb:6f:
                    1c:d2:e8:72:fb:fb:38:50:d4:1d:96:62:3a:7c:33:
                    85:ab:d9:2e:43:84:3e:31:fc:a2:32:07:d6:46:f5:
                    03:82:ec:4c:47
                ASN1 OID: secp256k1
        X509v3 extensions:
            X509v3 Subject Alternative Name: 
                DirName:/SN=1-ShaEk|2-ShaEk|3-ShaEk/UID=311190293700003/title=1100/registeredAddress=jazan/businessCategory=Tech
            X509v3 Subject Key Identifier: 
                09:F4:7E:9E:8F:A1:35:95:B3:AE:4F:E4:46:E9:62:3D:C8:7A:DD:01
            X509v3 Authority Key Identifier: 
                keyid:C7:C0:E6:B7:A9:DD:12:CA:4F:3D:6D:68:82:96:21:45:F3:01:75:A4

            X509v3 CRL Distribution Points: 

                Full Name:
                  URI:ldap:///CN=PEZEINVOICESCA4-CA(1),CN=PRZEINVOICEPKI4,CN=CDP,CN=Public%20Key%20Services,CN=Services,CN=Configuration,DC=extzatca,DC=gov,DC=local?certificateRevocationList?base?objectClass=cRLDistributionPoint

            Authority Information Access: 
                CA Issuers - URI:ldap:///CN=PEZEINVOICESCA4-CA,CN=AIA,CN=Public%20Key%20Services,CN=Services,CN=Configuration,DC=extzatca,DC=gov,DC=local?cACertificate?base?objectClass=certificationAuthority

            X509v3 Key Usage: critical
                Digital Signature
            1.3.6.1.4.1.311.21.7: 
                0-.%+.....7.............$......Uf...-...]..d...
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication, Code Signing
            1.3.6.1.4.1.311.21.10: 
                0.0
..+.......0
..+.......
    Signature Algorithm: ecdsa-with-SHA256
         30:46:02:21:00:da:c5:60:54:98:9d:85:7f:25:9c:ab:21:54:
         1e:09:2f:b6:01:63:e1:75:a7:8f:09:23:b3:4f:a4:ee:31:24:
         34:02:21:00:96:7f:de:cb:60:d1:0a:ef:7e:7c:9a:c7:c0:44:
         ad:62:4e:9d:e8:9b:c7:e7:27:7d:c0:e7:d4:ae:ad:18:c4:34

this is the signature value :

enter image description here

the problem now , that this is a string, is there a way easier than this , that gives me object or something like that ?

i have tried openssl_x509_parse also , but it does not give me the signature


Solution

  • phpseclib allows the direct determination of the certificate signature, s. Reading Certificates in the phpseclib documentation.

    The certificate is loaded with X509#loadX509() which returns an array with the three certificate fields tbsCertificate, signatureAlgorithm and signature (s. RFC 5280). The latter contains the signature.

    Sample code:

    use phpseclib3\File\X509;
    
    $certPem = "-----BEGIN CERTIFICATE-----
    MIIEvzCCBGSgAwIBAgITeAAARlJXpwVPUYDkbAABAABGUjAKBggqhkjOPQQDAjBi
    MRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxEzARBgoJkiaJk/IsZAEZFgNnb3YxFzAV
    BgoJkiaJk/IsZAEZFgdleHRnYXp0MRswGQYDVQQDExJQRVpFSU5WT0lDRVNDQTQt
    Q0EwHhcNMjQwNzAyMDMxMTE2WhcNMjYwNzAyMDMyMTE2WjBJMQswCQYDVQQGEwJT
    QTESMBAGA1UEChMJZnJlZSB0ZXh0MRIwEAYDVQQLEwlmcmVlIHRleHQxEjAQBgNV
    BAMTCWZyZWUgdGV4dDBWMBAGByqGSM49AgEGBSuBBAAKA0IABP/Lh6KN1Y5Z6CzW
    +3hLkwGLUyorKQoCCQZzrbtvHNLocvv7OFDUHZZiOnwzhavZLkOEPjH8ojIH1kb1
    A4LsTEejggMTMIIDDzB+BgNVHREEdzB1pHMwcTEgMB4GA1UEBAwXMS1TaGFFa3wy
    LVNoYUVrfDMtU2hhRWsxHzAdBgoJkiaJk/IsZAEBDA8zMTExOTAyOTM3MDAwMDMx
    DTALBgNVBAwMBDExMDAxDjAMBgNVBBoMBWphemFuMQ0wCwYDVQQPDARUZWNoMB0G
    A1UdDgQWBBQJ9H6ej6E1lbOuT+RG6WI9yHrdATAfBgNVHSMEGDAWgBTHwOa3qd0S
    yk89bWiCliFF8wF1pDCB5QYDVR0fBIHdMIHaMIHXoIHUoIHRhoHObGRhcDovLy9D
    Tj1QRVpFSU5WT0lDRVNDQTQtQ0EoMSksQ049UFJaRUlOVk9JQ0VQS0k0LENOPUNE
    UCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25m
    aWd1cmF0aW9uLERDPWV4dHphdGNhLERDPWdvdixEQz1sb2NhbD9jZXJ0aWZpY2F0
    ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9u
    UG9pbnQwgc4GCCsGAQUFBwEBBIHBMIG+MIG7BggrBgEFBQcwAoaBrmxkYXA6Ly8v
    Q049UEVaRUlOVk9JQ0VTQ0E0LUNBLENOPUFJQSxDTj1QdWJsaWMlMjBLZXklMjBT
    ZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPWV4dHphdGNh
    LERDPWdvdixEQz1sb2NhbD9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9
    Y2VydGlmaWNhdGlvbkF1dGhvcml0eTAOBgNVHQ8BAf8EBAMCB4AwPAYJKwYBBAGC
    NxUHBC8wLQYlKwYBBAGCNxUIgYaoHYTQ+xKG7Z0kh877GdPAVWaBnNgtg+XFXQIB
    ZAIBEDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwMwJwYJKwYBBAGCNxUK
    BBowGDAKBggrBgEFBQcDAjAKBggrBgEFBQcDAzAKBggqhkjOPQQDAgNJADBGAiEA
    2sVgVJidhX8lnKshVB4JL7YBY+F1p48JI7NPpO4xJDQCIQCWf97LYNEK7358msfA
    RK1iTp3om8fnJ33A59SurRjENA==
    -----END CERTIFICATE-----";
    
    $x509 = new X509();
    $cert = $x509->loadX509($certPem);
    $signature = $cert["signature"];
    print(bin2hex($signature) . PHP_EOL); // 003046022100dac56054989d857f259cab21541e092fb60163e175a78f0923b34fa4ee312434022100967fdecb60d10aef7e7c9ac7c044ad624e9de89bc7e7277dc0e7d4aead18c434
    
    $signature = substr($signature, 1);   // remove leading 0x00
    print(bin2hex($signature) . PHP_EOL); // 3046022100dac56054989d857f259cab21541e092fb60163e175a78f0923b34fa4ee312434022100967fdecb60d10aef7e7c9ac7c044ad624e9de89bc7e7277dc0e7d4aead18c434
    

    For the certificate posted, the signature is an ECDSA signature in ASN.1/DER format, which you can analyze in an ASN.1 parser, e.g. here.

    Note that for some reason a leading 0x00 is prepended (maybe the last byte of the preceding BIT STRING encoding 0x034900, s. here), which should be removed for a valid ASN.1/DER signature format.