117 lines
3.6 KiB
Go
117 lines
3.6 KiB
Go
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package protoutil
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/hyperledger/fabric-protos-go/common"
|
|
"github.com/hyperledger/fabric-protos-go/msp"
|
|
)
|
|
|
|
// SignedData is used to represent the general triplet required to verify a signature
|
|
// This is intended to be generic across crypto schemes, while most crypto schemes will
|
|
// include the signing identity and a nonce within the Data, this is left to the crypto
|
|
// implementation.
|
|
type SignedData struct {
|
|
Data []byte
|
|
Identity []byte
|
|
Signature []byte
|
|
}
|
|
|
|
// ConfigUpdateEnvelopeAsSignedData returns the set of signatures for the
|
|
// ConfigUpdateEnvelope as SignedData or an error indicating why this was not
|
|
// possible.
|
|
func ConfigUpdateEnvelopeAsSignedData(ce *common.ConfigUpdateEnvelope) ([]*SignedData, error) {
|
|
if ce == nil {
|
|
return nil, fmt.Errorf("No signatures for nil SignedConfigItem")
|
|
}
|
|
|
|
result := make([]*SignedData, len(ce.Signatures))
|
|
for i, configSig := range ce.Signatures {
|
|
sigHeader := &common.SignatureHeader{}
|
|
err := proto.Unmarshal(configSig.SignatureHeader, sigHeader)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result[i] = &SignedData{
|
|
Data: bytes.Join([][]byte{configSig.SignatureHeader, ce.ConfigUpdate}, nil),
|
|
Identity: sigHeader.Creator,
|
|
Signature: configSig.Signature,
|
|
}
|
|
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// EnvelopeAsSignedData returns the signatures for the Envelope as SignedData
|
|
// slice of length 1 or an error indicating why this was not possible.
|
|
func EnvelopeAsSignedData(env *common.Envelope) ([]*SignedData, error) {
|
|
if env == nil {
|
|
return nil, fmt.Errorf("No signatures for nil Envelope")
|
|
}
|
|
|
|
payload := &common.Payload{}
|
|
err := proto.Unmarshal(env.Payload, payload)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if payload.Header == nil /* || payload.Header.SignatureHeader == nil */ {
|
|
return nil, fmt.Errorf("Missing Header")
|
|
}
|
|
|
|
shdr := &common.SignatureHeader{}
|
|
err = proto.Unmarshal(payload.Header.SignatureHeader, shdr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("GetSignatureHeaderFromBytes failed, err %s", err)
|
|
}
|
|
|
|
return []*SignedData{{
|
|
Data: env.Payload,
|
|
Identity: shdr.Creator,
|
|
Signature: env.Signature,
|
|
}}, nil
|
|
}
|
|
|
|
// LogMessageForSerializedIdentity returns a string with seriealized identity information,
|
|
// or a string indicating why the serialized identity information cannot be returned.
|
|
// Any errors are intentially returned in the return strings so that the function can be used in single-line log messages with minimal clutter.
|
|
func LogMessageForSerializedIdentity(serializedIdentity []byte) string {
|
|
id := &msp.SerializedIdentity{}
|
|
err := proto.Unmarshal(serializedIdentity, id)
|
|
if err != nil {
|
|
return fmt.Sprintf("Could not unmarshal serialized identity: %s", err)
|
|
}
|
|
pemBlock, _ := pem.Decode(id.IdBytes)
|
|
if pemBlock == nil {
|
|
// not all identities are certificates so simply log the serialized
|
|
// identity bytes
|
|
return fmt.Sprintf("serialized-identity=%x", serializedIdentity)
|
|
}
|
|
cert, err := x509.ParseCertificate(pemBlock.Bytes)
|
|
if err != nil {
|
|
return fmt.Sprintf("Could not parse certificate: %s", err)
|
|
}
|
|
return fmt.Sprintf("(mspid=%s subject=%s issuer=%s serialnumber=%d)", id.Mspid, cert.Subject, cert.Issuer, cert.SerialNumber)
|
|
}
|
|
|
|
func LogMessageForSerializedIdentities(signedData []*SignedData) (logMsg string) {
|
|
var identityMessages []string
|
|
for _, sd := range signedData {
|
|
identityMessages = append(identityMessages, LogMessageForSerializedIdentity(sd.Identity))
|
|
}
|
|
return strings.Join(identityMessages, ", ")
|
|
}
|