内容简介: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)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Go 之如何操作结构体的非导出字段
- ASP.NET 开源导入导出库Magicodes.IE 导出Pdf教程
- MrDoc 0.5.0 版本发布,优化 EPUB 导出,新增 PDF 导出,支持自定义思维导图
- php 导出 excel
- oracle导出序列sequence
- vue导出excel表格
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
你不知道的JavaScript(上卷)
[美] Kyle Simpson / 赵望野、梁杰 / 人民邮电出版社 / 2015-4 / 49.00元
JavaScript语言有很多复杂的概念,但却用简单的方式体现出来(比如回调函数),因此,JavaScript开发者无需理解语言内部的原理,就能编写出功能全面的程序;就像收音机一样,你无需理解里面的管子和线圈都是做什么用的,只要会操作收音机上的按键,就可以收听你喜欢的节目。然而,JavaScript的这些复杂精妙的概念才是语言的精髓,即使是经验丰富的JavaScript开发者,如果没有认真学习也无......一起来看看 《你不知道的JavaScript(上卷)》 这本书的介绍吧!