storj/pkg/auth/signedMessage.go

86 lines
2.4 KiB
Go
Raw Normal View History

// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
package auth
import (
"crypto/ecdsa"
"crypto/x509"
"github.com/gtank/cryptopasta"
"github.com/zeebo/errs"
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/peertls"
"storj.io/storj/pkg/storj"
)
var (
//ECDSA indicates a key was not an ECDSA key
ECDSA = errs.New("Key is not ecdsa key")
//Sign indicates a failure during signing
Sign = errs.Class("Failed to sign message")
//Verify indicates a failure during signature validation
Verify = errs.Class("Failed to validate message signature")
//SigLen indicates an invalid signature length
SigLen = errs.Class("Invalid signature length")
//Serial indicates an invalid serial number length
Serial = errs.Class("Invalid SerialNumber")
//Expired indicates the agreement is expired
Expired = errs.Class("Agreement is expired")
//Signer indicates a public key / node id mismatch
Signer = errs.Class("Message public key did not match expected signer")
//BadID indicates a public key / node id mismatch
BadID = errs.Class("Node ID did not match expected id")
)
//VerifyMsg checks the crypto-related aspects of signed message
func VerifyMsg(sm pb.SignedMsg, signer storj.NodeID) error {
//no null fields
if ok, err := pb.MsgComplete(sm); !ok {
return err
}
certs := sm.GetCerts()
if len(certs) < 2 {
return Verify.New("Expected at least leaf and CA public keys")
}
//correct signature length
err := peertls.VerifyPeerFunc(peertls.VerifyPeerCertChains)(certs, nil)
if err != nil {
return Verify.Wrap(err)
}
leafPubKey, err := parseECDSA(certs[0])
if err != nil {
return err
}
caPubKey, err := parseECDSA(certs[1])
if err != nil {
return err
}
signatureLength := leafPubKey.Curve.Params().P.BitLen() / 8
if len(sm.GetSignature()) < signatureLength {
return SigLen.New("%s", sm.GetSignature())
}
// verify signature
if id, err := identity.NodeIDFromECDSAKey(caPubKey); err != nil || id != signer {
return Signer.New("%+v vs %+v", id, signer)
}
if ok := cryptopasta.Verify(sm.GetData(), sm.GetSignature(), leafPubKey); !ok {
return Verify.New("%+v", ok)
}
return nil
}
func parseECDSA(rawCert []byte) (*ecdsa.PublicKey, error) {
cert, err := x509.ParseCertificate(rawCert)
if err != nil {
return nil, Verify.Wrap(err)
}
ecdsa, ok := cert.PublicKey.(*ecdsa.PublicKey)
if !ok {
return nil, ECDSA
}
return ecdsa, nil
}