Fabric认证失败的问题:certificate signed by unknown authority
在调试fabric的时候我们经常会碰到证书认证失败的问题,例如:
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 "peer0.org0.example.com"))
或者
Error: Failed to deserialize creator identity, err The supplied identity is not valid,
Verify() returned x509: certificate signed by unknown authority
(possibly because of "x509: ECDSA verification failure"
while trying to verify candidate authority certificate "peer1.org1.example.com")
等等,这些错误,
然后会打印出identity信息,如下格式:
0a0a53616d654f72674d535012fb062d2d2d2d2d ...... 3d3d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a
我就想知道到底客户端发来的证书是什么内容,是不是正确的证书,而orderer/peer打印出来的证书内容是identity的序列号后的内容,显然是看不懂的;所以每回我都要进去改orderer或者peer的源代码,在相应位置把identity转换成PEM,然后再把PEM内容打出来,变成一个通用的文本。但是每回改源代码重编译再重新运行是个繁琐的过程。
所以这里开发一个小工具输入identity的序列化后的内容,输出PEM格式文本。这样每次看到日志报错的时候,直接把屏幕打出来的identity的字符序列拷贝出来,用工具一翻译,就输出PEM格式证书,之后就可以用openssl的工具来访问操作PEM证书了。
package main
import (
"os"
"fmt"
"time"
"bufio"
"errors"
"math/big"
"crypto/x509/pkix"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"encoding/asn1"
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/protos/msp"
)
type validity struct {
NotBefore, NotAfter time.Time
}
type publicKeyInfo struct {
Raw asn1.RawContent
Algorithm pkix.AlgorithmIdentifier
PublicKey asn1.BitString
}
type certificate struct {
Raw asn1.RawContent
TBSCertificate tbsCertificate
SignatureAlgorithm pkix.AlgorithmIdentifier
SignatureValue asn1.BitString
}
type tbsCertificate struct {
Raw asn1.RawContent
Version int `asn1:"optional,explicit,default:0,tag:0"`
SerialNumber *big.Int
SignatureAlgorithm pkix.AlgorithmIdentifier
Issuer asn1.RawValue
Validity validity
Subject asn1.RawValue
PublicKey publicKeyInfo
UniqueId asn1.BitString `asn1:"optional,tag:1"`
SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"`
Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"`
}
func (c certificate) String() (string, error) {
b, err := asn1.Marshal(c)
if err != nil {
return "", err
}
block := &pem.Block{
Bytes: b,
Type: "CERTIFICATE",
}
b = pem.EncodeToMemory(block)
return string(b), err
}
func certToPEM(x509Cert *x509.Certificate) (string, error) {
var newCert certificate
_, err := asn1.Unmarshal(x509Cert.Raw, &newCert)
if err != nil {
return "", err
}
return newCert.String()
}
func getSerializedIdentityString(input string) (string, error) {
file, err := os.Open(input)
if err != nil {
return "", err
}
defer file.Close()
scanner := bufio.NewScanner(file)
scanner.Scan()
serializedIdentityString := scanner.Text()
if err := scanner.Err(); err != nil {
return "", err
}
return serializedIdentityString, nil
}
func DecodeIdentity(input string, output string) error {
var err error
serializedIdentityString, err := getSerializedIdentityString(input)
if err != nil {
return err
}
serializedIdentityBuffer, err := hex.DecodeString(serializedIdentityString)
if err != nil {
return err
}
serializedIdentity := &msp.SerializedIdentity{}
err = proto.Unmarshal(serializedIdentityBuffer, serializedIdentity)
if err != nil {
return err
}
pemBlock, _ := pem.Decode(serializedIdentity.IdBytes)
if pemBlock == nil {
return errors.New("could not decode the PEM structure")
}
x509Cert, err := x509.ParseCertificate(pemBlock.Bytes)
if err != nil {
return err
}
pemString, err := certToPEM(x509Cert)
if err != nil {
return err
}
fmt.Printf("MSP=%s\n", serializedIdentity.Mspid)
fmt.Printf("PEM=%s\n", pemString)
return nil
}
主函数是DecodeIdentity(),需要一个输入参数:
- input 是包含identity内容的文本文件,单行
- output 参数忽略
运行结果把mspID和PEM证书内容打印到屏幕。
这些代码都在fabric内部存在,我就是把他们考出来组织在一起,使得能够编译成一个可独立运行的小工具。