golang如何访问一个结构体(struct)的未导出域(field)

栏目: Go · 发布时间: 6年前

内容简介:golang如何访问一个结构体(struct)的未导出域(field)问题的引出在做fabric调试的时候,经常碰到证书验证失败的问题,看到orderer日志类似:

golang如何访问一个结构体(struct)的未导出域(field)

问题的引出

在做fabric调试的时候,经常碰到证书验证失败的问题,看到orderer日志类似:

<orderer>  | <timestampe> [cauthdsl] deduplicate -> ERRO 177 Principal deserialization failure (the supplied
 identity is not valid: x509: certificate signed by unknown authority (possibly because of "x509: ECDSA
 verification failure" while trying to verify candidate authority certificate "...")) for identity <identify content>

在这个过程中打出来的是被验证的证书的内容(通过前面文章我们知道可以从identity导出证书的PEM格式),但是没有打印出验证所需要的CA证书信息,怎么办呢。我们需要得到验证所用到的CA证书信息。

溯源CA证书信息

msp对象(实际是bccspmsp struct)包含一个成员opts:

# fabric/msp/mspimpl.go
type bccspmsp struct {
  ...
  // verification options for MSP members
  opts *x509.VerifyOptions
  ...
}

opts是一个x509.VerifyOptions对象。

# go/src/crypto/x509/verify.go
type VerifyOptions struct {
  ...
  Intermediates *CertPool
  Roots         *CertPool // if nil, the system roots are used
  ...
}

VerifyOptions包含一个Roots和Intermediates,这两个pool里面的证书是用来验证证书的根证书。正好这两个变量都是导出变量(首字母大写),可以直接使用。

下面看CertPool的定义。

# go/src/crypto/x509/cert_pool.go
type CertPool struct {
        bySubjectKeyId map[string][]int
        byName         map[string][]int
        certs          []*Certificate
}

我们看到所有的证书都存在certs这个域里面,他是一个slice类型变量,只是遗憾的是certs不是一个导出变量(首字母小写),导致在包(package)外面不能访问这个域;另外CertPool也没有定义函数用来返回certs域,所有CertPool定义的导出函数只有如下:

func (s *CertPool) AddCert(cert *Certificate)
func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool)
func (s *CertPool) Subjects() [][]byte

这不抓瞎了吗,明明certs就定义在那里已经看到了,但是就是访问不了;库的设计者为什么要这样折磨人呢,为什么不暴露一个API导出这个slice呢,基于什么原因呢?

当然有一个办法,我们手动添加一个导出函数,在cert_pool.go文件内,例如:

func (s *CertPool) Certs() []*Certificate {
  return c.certs
}

不过要提醒你的是,这可是golang的系统库啊,不是你的用户代码。请你不要随便改。

另一办法,就是本文要说的如何访问一个未导出域。

CertPool的certs是一个未导出域,我们已经得到了CertPool对象,并且知道他有一个域certs包含的就是CA证书列表,下面我们就是想办法访问这个未导出域。

访问未导出域

使用reflect包访问struct的未导出域。

package main

import (
    "fmt"
    "reflect"
    "unsafe"
    "crypto/x509"
)

func main() {
    var certPool *x509.CertPool
    var err error
    if certPool, err = x509.SystemCertPool(); err != nil {
        panic(err)
    }

    var reflectStruct reflect.Value = reflect.ValueOf(certPool).Elem()
    var reflectField reflect.Value = reflectStruct.FieldByName("certs")

    fmt.Printf("reflectStruct type=[%v]\n", reflectStruct.Type())
    fmt.Printf("reflectField  type=[%v]\n", reflectField.Type())

    reflectField = reflect.NewAt(reflectField.Type(), unsafe.Pointer(reflectField.UnsafeAddr()))
    reflectField = reflectField.Elem()

    var certs []*x509.Certificate = reflectField.Interface().([]*x509.Certificate)
    fmt.Printf("Total Certificate: %d\n", len(certs))
    for i, cert := range certs {
        if content, err := certToPEM(cert); err != nil {
            panic(err)
        } else {
            fmt.Printf("Certificate[%d]=[%s]\n", i, content)
        }
    }
}

几个API:

  • func ValueOf(i interface{}) Value
    ValueOf returns a new Value initialized to the concrete value stored in the interface i
  • func (v Value) Elem() Value
    Elem returns the value that the interface v contains or that the pointer v points to
  • func (v Value) Interface() (i interface{})
    Interface returns v's current value as an interface{}
  • func NewAt(typ Type, p unsafe.Pointer) Value
    NewAt returns a Value representing a pointer to a value of the specified type, using p as that pointer

以上所述就是小编给大家介绍的《golang如何访问一个结构体(struct)的未导出域(field)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Software Engineering for Internet Applications

Software Engineering for Internet Applications

Eve Andersson、Philip Greenspun、Andrew Grumet / The MIT Press / 2006-03-06 / USD 35.00

After completing this self-contained course on server-based Internet applications software, students who start with only the knowledge of how to write and debug a computer program will have learned ho......一起来看看 《Software Engineering for Internet Applications》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

SHA 加密
SHA 加密

SHA 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具