Golang中正确解码asn1.RawValue的方法(X509证书解析场景)
Go解析X509证书AIA扩展时的乱码解决方法
问题背景
我正在使用Golang实现证书解析,需要获取父证书链接。执行openssl x509 -in certificate.pem -text -noout可查看证书的**Authority Information Access(AIA)**扩展,其中包含OCSP和CA Issuers的URI。
我的Go项目代码如下:
package main import ( "encoding/asn1" "encoding/pem" "fmt" "crypto/x509" ) func main() { content := `-----BEGIN CERTIFICATE----- MIIJxDCCCKygAwIBAgINfEbzVUOoCNMWumANCjANBgkqhkiG9w0BAQsFADBqMQsw CQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2Vj IEx0ZC4xFDASBgNVBAsMC2UtU3ppZ25vIENBMRowGAYDVQQDDBFlLVN6aWdubyBU ZXN0IENBMzAeFw0yMzAxMjQxMjQxNTBaFw0yNDAxMjQxMjQxNTBaMIHQMRMwEQYL KwYBBAGCNzwCAQMTAkVFMRgwFgYLKwYBBAGCNzwCAQEMB1RhbGxpbm4xHTAbBgNV BA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMREwDwYDVQQFEwgxMjI2ODQ3NTELMAkG A1UEBhMCRUUxEDAOBgNVBAcMB1RhbGxpbm4xFzAVBgNVBAoMDk1ha3Nla2Vza3Vz IEFTMRswGQYDVQRhDBJQU0RFRS1GU0EtMTIyNjg0NzUxGDAWBgNVBAMMD21ha2Vj b21tZXJjZS5sdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJFyj3sS xev2yHbGXNmqw8e+ZqFvrb1+UHlsm7c65HSjwAVjheHNV1cufilRf5X1PuBDmXtC XpwD7FmOc7h++BAEdapv/XcWkMqUgbkfwhaZPkjbXIQBH7jbe4D+3pxn+ZDlq/1b Wi6dJhGHN+Ydgw6x+qGBOVzaFlprFdOYQXDw8yMc/iQMBahzzQApe2EwW1XRgyaT DNE5t2T7uWC05qDYgi1HI50WGoezx7A7CDSjwG+kFvczleY+4H73aPiGH1f0q+EC POZsoot12CWspBwZB9G03S5IoIipJPoQmIvnKGgeGbbY16P3VQ/78w9XjPy0dwid x2CfPlPLTa8eJF0CAwEAAaOCBgAwggX8MA4GA1UdDwEB/wQEAwIFoDCBiQYKKwYB BAHWeQIEAgR7BHkAdwB1AKoeeAQ/gGSCK+VMtcHKwuMu5FDmczAqSLwmlwubLAgd AAABhePMiCsAAAQDAEYwRAIgMbv+IXdcxOgT9VPPUIuuHajA08AiGnQMKnSsYHPl 4egCICQN64jfx+fitpnfxb6u531tA3VkjmMmLOkvN5b2vj4wMB0GA1UdJQQWMBQG CCsGAQUFBwMBBggrBgEFBQcDAjCCAyQGA1UdIASCAxswggMXMIIDEwYMKwYBBAGB qBgCAQFkMIIDATAmBggrBgEFBQcCARYaaHR0cDovL2NwLmUtc3ppZ25vLmh1L3Fj cHMwgb8GCCsGAQUFBwICMIGyDIGvVGVzdCBxdWFsaWZpZWQgY2VydGlmaWNhdGUg Zm9yIHdlYnNpdGUgYXV0aGVudGljYXRpb24gYW5kIGNsaWVudCBhdXRoZW50aWNh dGlvbi4gVGhlIHByb3ZpZGVyIHByZXNlcnZlcyByZWdpc3RyYXRpb24gZGF0YSBm b3IgMTAgeWVhcnMgYWZ0ZXIgdGhlIGV4cGlyYXRpb24gb2YgdGhlIGNlcnRpZmlj YXRlLjCBlQYIKwYBBQUHAgIwgYgMgYVURVNUIGNlcnRpZmljYXRlIGlzc3VlZCBv bmx5IGZvciB0ZXN0aW5nIHB1cnBvc2VzLiBUaGUgaXNzdWVyIGlzIG5vdCBsaWFi bGUgZm9yIGFueSBkYW1hZ2VzIGFyaXNpbmcgZnJvbSB0aGUgdXNlIG9mIHRoaXMg Y2VydGlmaWNhdGUhMIHMBggrBgEFBQcCAjCBvwyBvFRlc3p0IG1pbsWRc8OtdGV0 dCB3ZWJvbGRhbC1oaXRlbGVzw610xZEgw6lzIMO8Z3lmw6lsLWhpdGVsZXPDrXTF kSB0YW7DunPDrXR2w6FueS4gQSByZWdpc3p0csOhY2nDs3MgYWRhdG9rYXQgYSBz em9sZ8OhbHRhdMOzIGEgdGFuw7pzw610dsOhbnkgbGVqw6FydMOhdMOzbCBzesOh bcOtdG90dCAxMCDDqXZpZyDFkXJ6aSBtZWcuMIGtBggrBgEFBQcCAjCBoAyBnVRl c3p0ZWzDqXNpIGPDqWxyYSBraWFkb3R0IFRFU1pUIHRhbsO6c8OtdHbDoW55LiBB IGhhc3puw6FsYXTDoXZhbCBrYXBjc29sYXRvc2FuIGZlbG1lcsO8bMWRIGvDoXJv a8OpcnQgYSBTem9sZ8OhbHRhdMOzIHNlbW1pbHllbiBmZWxlbMWRc3PDqWdldCBu ZW0gdsOhbGxhbCEwHQYDVR0OBBYEFFpdJ86Z7qiDATzBzLvlL+6RLl12MB8GA1Ud IwQYMBaAFNzmAijvNzCPiT6grSBV8+826PDNMBoGA1UdEQQTMBGCD21ha2Vjb21t ZXJjZS5sdDAyBgNVHR8EKzApMCegJaAjhiFodHRwOi8vdGVzenQuZS1zemlnbm8u aHUvVENBMy5jcmwwbwYIKwYBBQUHAQEEYzBhMDAGCCsGAQUFBzABhiRodHRwOi8v dGVzenQuZS1zemlnbm8uaHUvdGVzdGNhM29jc3AwLQYIKwYBBQUHMAKGIWh0dHA6 Ly90ZXN6dC5lLXN6aWduby5odS9UQ0EzLmNydDCCARQGCCsGAQUFBwEDBIIBBjCC AQIwCAYGBACORgEBMAsGBgQAjkYBAwIBCjBTBgYEAI5GAQUwSTAkFh5odHRwczov L2NwLmUtc3ppZ25vLmh1L3FjcHNfZW4TAkVOMCEWG2h0dHBzOi8vY3AuZS1zemln bm8uaHUvcWNwcxMCSFUwEwYGBACORgEGMAkGBwQAjkYBBgMwfwYGBACBmCcCMHUw JjARBgcEAIGYJwECDAZQU1BfUEkwEQYHBACBmCcBAwwGUFNQX0FJDENFRSAtIEVz dG9uaWFuIEZpbmFuY2lhbCBTdXBlcnZpc2lvbiBBdXRob3JpdHkgLyBGaW5hbnRz aW5zcGVrdHNpb29uDAZFRS1GU0EwDQYJKoZIhvcNAQELBQADggEBAHZXm9440SvU cpZLshQ3oKOOeU4fTrP0KQkvzmBkmf+yct80vartjnIaDk5rk6HQRJRjcuDI9+Hj ep9nzwkN+BUVwc2EV+M7i35pCK+dvNMTcgXTo2qGVznoSVjFuzshoC4mFIfxNczo 2NE2uTfU2wyWzQPYNcwFMZ7AoUXylGofEfS13mdH5dET++nWoAOD8ABZZqAeYsk9 R1fCxRThpldxjiJdDUZpzcVw+obyjRhKIm6zAHd6R0E6KB9I+feevF8IwgnTSozE Zflb6EvyjuizsyqGteLrjim4ALu1+pA/2zhLZm55PWj1kM8PiWYqIGla0dKOzF4+ OTNNT6RR7bU= -----END CERTIFICATE-----` certDERBlock, _ := pem.Decode([]byte(content)) x509Cert, err := x509.ParseCertificate(certDERBlock.Bytes) if err != nil { fmt.Println("Parse certificate error:", err) return } for _, extension := range x509Cert.Extensions { if extension.Id.Equal(asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 1}) { var collExts []asn1.RawValue asn1.Unmarshal(extension.Value, &collExts) for _, collExt := range collExts { fmt.Println(string(collExt.Bytes)) } } } }
运行后输出带乱码的内容:
+0�#http://teszt.e-szigno.hu/testca3ocsp +0�0http://teszt.e-szigno.hu/TCA3.crt
虽然可以自行提取链接,但希望了解如何正确解码asn1.RawValue或其Bytes字段,得到可读的文本内容。查阅了asn1包,未找到对应的解码函数。
解决方案
AIA扩展的ASN.1结构包含多个条目,每个条目由OID和IA5String类型的URI组成。直接将RawValue的Bytes转字符串会包含ASN.1的类型标签和长度信息,导致乱码。正确的做法是定义匹配ASN.1结构的Go结构体,通过asn1.Unmarshal完成解码。
修改后的代码
package main import ( "encoding/asn1" "encoding/pem" "fmt" "crypto/x509" "log" ) // AIAEntry 表示AIA扩展中的单个条目 type AIAEntry struct { OID asn1.ObjectIdentifier URI string `asn1:"ia5string"` } // AIAContent 表示整个AIA扩展的内容 type AIAContent struct { Entries []AIAEntry `asn1:"sequence"` } func main() { content := `-----BEGIN CERTIFICATE----- MIIJxDCCCKygAwIBAgINfEbzVUOoCNMWumANCjANBgkqhkiG9w0BAQsFADBqMQsw CQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2Vj IEx0ZC4xFDASBgNVBAsMC2UtU3ppZ25vIENBMRowGAYDVQQDDBFlLVN6aWdubyBU ZXN0IENBMzAeFw0yMzAxMjQxMjQxNTBaFw0yNDAxMjQxMjQxNTBaMIHQMRMwEQYL KwYBBAGCNzwCAQMTAkVFMRgwFgYLKwYBBAGCNzwCAQEMB1RhbGxpbm4xHTAbBgNV BA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMREwDwYDVQQFEwgxMjI2ODQ3NTELMAkG A1UEBhMCRUUxEDAOBgNVBAcMB1RhbGxpbm4xFzAVBgNVBAoMDk1ha3Nla2Vza3Vz IEFTMRswGQYDVQRhDBJQU0RFRS1GU0EtMTIyNjg0NzUxGDAWBgNVBAMMD21ha2Vj b21tZXJjZS5sdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJFyj3sS xev2yHbGXNmqw8e+ZqFvrb1+UHlsm7c65HSjwAVjheHNV1cufilRf5X1PuBDmXtC XpwD7FmOc7h++BAEdapv/XcWkMqUgbkfwhaZPkjbXIQBH7jbe4D+3pxn+ZDlq/1b Wi6dJhGHN+Ydgw6x+qGBOVzaFlprFdOYQXDw8yMc/iQMBahzzQApe2EwW1XRgyaT DNE5t2T7uWC05qDYgi1HI50WGoezx7A7CDSjwG+kFvczleY+4H73aPiGH1f0q+EC POZsoot12CWspBwZB9G03S5IoIipJPoQmIvnKGgeGbbY16P3VQ/78w9XjPy0dwid x2CfPlPLTa8eJF0CAwEAAaOCBgAwggX8MA4GA1UdDwEB/wQEAwIFoDCBiQYKKwYB BAHWeQIEAgR7BHkAdwB1AKoeeAQ/gGSCK+VMtcHKwuMu5FDmczAqSLwmlwubLAgd AAABhePMiCsAAAQDAEYwRAIgMbv+IXdcxOgT9VPPUIuuHajA08AiGnQMKnSsYHPl 4egCICQN64jfx+fitpnfxb6u531tA3VkjmMmLOkvN5b2vj4wMB0GA1UdJQQWMBQG CCsGAQUFBwMBBggrBgEFBQcDAjCCAyQGA1UdIASCAxswggMXMIIDEwYMKwYBBAGB qBgCAQFkMIIDATAmBggrBgEFBQcCARYaaHR0cDovL2NwLmUtc3ppZ25vLmh1L3Fj cHMwgb8GCCsGAQUFBwICMIGyDIGvVGVzdCBxdWFsaWZpZWQgY2VydGlmaWNhdGUg Zm9yIHdlYnNpdGUgYXV0aGVudGljYXRpb24gYW5kIGNsaWVudCBhdXRoZW50aWNh dGlvbi4gVGhlIHByb3ZpZGVyIHByZXNlcnZlcyByZWdpc3RyYXRpb24gZGF0YSBm b3IgMTAgeWVhcnMgYWZ0ZXIgdGhlIGV4cGlyYXRpb24gb2YgdGhlIGNlcnRpZmlj YXRlLjCBlQYIKwYBBQUHAgIwgYgMgYVURVNUIGNlcnRpZmljYXRlIGlzc3VlZCBv bmx5IGZvciB0ZXN0aW5nIHB1cnBvc2VzLiBUaGUgaXNzdWVyIGlzIG5vdCBsaWFi bGUgZm9yIGFueSBkYW1hZ2VzIGFyaXNpbmcgZnJvbSB0
相关产品推荐
相关产品推荐

