86 lines
2.4 KiB
Go
86 lines
2.4 KiB
Go
|
// 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
|
||
|
}
|