简述
任务:在实际开发中需要使用golang读取证书中SubjectAlternativeNames字段的内容。标准证书是由ASN1编码生成的,Java可以使用java.security.cert包中的X509Certificate类中getSubjectAlternativeNames()方法来提取这个扩展字段的内容。golang官方库中提供了X509这个包来实现asn1编码,其所对应的证书字段为:
// A Certificate represents an X.509 certificate.
type Certificate struct {
Raw []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature).
RawTBSCertificate []byte // Certificate part of raw ASN.1 DER content.
RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo.
RawSubject []byte // DER encoded Subject
RawIssuer []byte // DER encoded Issuer
Signature []byte
SignatureAlgorithm SignatureAlgorithm
PublicKeyAlgorithm PublicKeyAlgorithm
PublicKey interface{}
Version int
SerialNumber *big.Int
Issuer pkix.Name
Subject pkix.Name
NotBefore, NotAfter time.Time // Validity bounds.
KeyUsage KeyUsage
// Extensions contains raw X.509 extensions. When parsing certificates,
// this can be used to extract non-critical extensions that are not
// parsed by this package. When marshaling certificates, the Extensions
// field is ignored, see ExtraExtensions.
Extensions []pkix.Extension
// ExtraExtensions contains extensions to be copied, raw, into any
// marshaled certificates. Values override any extensions that would
// otherwise be produced based on the other fields. The ExtraExtensions
// field is not populated when parsing certificates, see Extensions.
ExtraExtensions []pkix.Extension
// UnhandledCriticalExtensions contains a list of extension IDs that
// were not (fully) processed when parsing. Verify will fail if this
// slice is non-empty, unless verification is delegated to an OS
// library which understands all the critical extensions.
//
// Users can access these extensions using Extensions and can remove
// elements from this slice if they believe that they have been
// handled.
UnhandledCriticalExtensions []asn1.ObjectIdentifier
ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages.
UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package.
// BasicConstraintsValid indicates whether IsCA, MaxPathLen,
// and MaxPathLenZero are valid.
BasicConstraintsValid bool
IsCA bool
// MaxPathLen and MaxPathLenZero indicate the presence and
// value of the BasicConstraints' "pathLenConstraint".
//
// When parsing a certificate, a positive non-zero MaxPathLen
// means that the field was specified, -1 means it was unset,
// and MaxPathLenZero being true mean that the field was
// explicitly set to zero. The case of MaxPathLen==0 with MaxPathLenZero==false
// should be treated equivalent to -1 (unset).
//
// When generating a certificate, an unset pathLenConstraint
// can be requested with either MaxPathLen == -1 or using the
// zero value for both MaxPathLen and MaxPathLenZero.
MaxPathLen int
// MaxPathLenZero indicates that BasicConstraintsValid==true
// and MaxPathLen==0 should be interpreted as an actual
// maximum path length of zero. Otherwise, that combination is
// interpreted as MaxPathLen not being set.
MaxPathLenZero bool
SubjectKeyId []byte
AuthorityKeyId []byte
// RFC 5280, 4.2.2.1 (Authority Information Access)
OCSPServer []string
IssuingCertificateURL []string
// Subject Alternate Name values. (Note that these values may not be valid
// if invalid values were contained within a parsed certificate. For
// example, an element of DNSNames may not be a valid DNS domain name.)
DNSNames []string
EmailAddresses []string
IPAddresses []net.IP
URIs []*url.URL
// Name constraints
PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical.
PermittedDNSDomains []string
ExcludedDNSDomains []string
PermittedIPRanges []*net.IPNet
ExcludedIPRanges []*net.IPNet
PermittedEmailAddresses []string
ExcludedEmailAddresses []string
PermittedURIDomains []string
ExcludedURIDomains []string
// CRL Distribution Points
CRLDistributionPoints []string
PolicyIdentifiers []asn1.ObjectIdentifier
}
通过查阅相关的文档,我发现golang中的Extensions即x509证书中的扩展项,如果要读取证书中这个字段的内容,只需要直接使用如下的代码:
certDERBlock, _ := pem.Decode(cert)//cert为byte数组,证书字节流
x509Cert, _ := x509.ParseCertificate(certDERBlock.Bytes)
strTemp := x509Cert.Extensions //取得了扩展字段
此时,回到最初的问题,我们需要从Java中对应的代码中取得SubjectAlternativeNames,在Java中debug定位发现,存入扩展字段中的需要提取的目的字段为:
[5]: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
IPAddress: 10.33.102.9
URIName: http://SecurityMgmtMicroService.SecurityMgmtService.huawei.com
]
从这里可以看出,该字段对应的asn1.ObjectIdentifier为2.5.29.17(注意:一个ObjectIdentifier表示一个 ASN.1 对象标识符。),因此可以采用如下的方式发现这个字段
for _, value := range strTemp
if strings.Compare(value.Id.String() , "2.5.29.17") == 0{
}
提取了这个字段之后,该如何解析这个字段的内容呢?
此时需要使用ASN1反序列化解析,要与生成证书中ASN1序列化的方式一一对应。针对我面临的问题,使用如下的方式反序列化:
for _, value := range strTemp {
if strings.Compare(value.Id.String(), "2.5.29.17") == 0 {
var val []asn1.RawValue
_, err1 := asn1.Unmarshal(value.Value, &val)
if err1 != nil {
log.Print(err1)
}
for _, asnVal := range val {
strA := string(asnVal.Bytes)
if strings.Contains(strA, "http://") {
nameUrl := strA[len("http://"):]
nameArr := strings.Split(nameUrl, ".")
microServiceName = nameArr[0]
serviceName = nameArr[1]
break
} else{
microServiceName = ""
serviceName = ""
}
}
}
}
总结
证书如果按照X509标准来生成,go中提供了ASN1库来序列化和反序列化证书中的字段内容。