Skip to content

Commit

Permalink
[FAB-9938] Add req method and uri to sig payload
Browse files Browse the repository at this point in the history
Currently, during OAuth token is of the form:
<base64 encoded user's cert>.<base64 encoding of the signature>
The signature is on the payload of the form:
<base64 encoding of request body>.<base64 encoding of user's cert>
This change changes the payload to add request method and URI to
make it more secure.
So, the  payload is form the form:
<request method>.<url path>.<base64 encoding of request body>.<base64 encoding of user's cert>

Change-Id: I3087d491e63b9f61d022d8ca0f7701c3987999ee
Signed-off-by: Anil Ambati <aambati@us.ibm.com>
  • Loading branch information
Anil Ambati committed May 15, 2018
1 parent 534af8c commit 02858a7
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 22 deletions.
2 changes: 1 addition & 1 deletion lib/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ func (i *Identity) addTokenAuthHdr(req *http.Request, body []byte) error {
log.Debug("Adding token-based authorization header")
cert := i.ecert.cert
key := i.ecert.key
token, err := util.CreateToken(i.CSP, cert, key, body)
token, err := util.CreateToken(i.CSP, cert, key, req.Method, req.URL.RequestURI(), body)
if err != nil {
return errors.WithMessage(err, "Failed to add token authorization header")
}
Expand Down
2 changes: 1 addition & 1 deletion lib/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,7 @@ func addTokenAuthHeader(req *http.Request, t *testing.T) {
t.Fatalf("Failed importing key %s", err)
}
emptyByte := make([]byte, 0)
token, err := util.CreateToken(CSP, cert, key, emptyByte)
token, err := util.CreateToken(CSP, cert, key, req.Method, req.URL.RequestURI(), emptyByte)
if err != nil {
t.Fatalf("Failed to add token authorization header: %s", err)
}
Expand Down
2 changes: 1 addition & 1 deletion lib/serverrequestcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func (ctx *serverRequestContext) TokenAuthentication() (string, error) {
return "", err
}
// Verify the token; the signature is over the header and body
cert, err2 := util.VerifyToken(ca.csp, authHdr, body)
cert, err2 := util.VerifyToken(ca.csp, authHdr, r.Method, r.URL.RequestURI(), body)
if err2 != nil {
return "", newAuthErr(ErrInvalidToken, "Invalid token in authorization header: %s", err2)
}
Expand Down
16 changes: 10 additions & 6 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,10 @@ func Unmarshal(from []byte, to interface{}, what string) error {
// which is the body of an HTTP request, though could be any arbitrary bytes.
// @param cert The pem-encoded certificate
// @param key The pem-encoded key
// @param method http method of the request
// @param uri URI of the request
// @param body The body of an HTTP request
func CreateToken(csp bccsp.BCCSP, cert []byte, key bccsp.Key, body []byte) (string, error) {
func CreateToken(csp bccsp.BCCSP, cert []byte, key bccsp.Key, method, uri string, body []byte) (string, error) {
x509Cert, err := GetX509CertificateFromPEM(cert)
if err != nil {
return "", err
Expand All @@ -189,7 +191,7 @@ func CreateToken(csp bccsp.BCCSP, cert []byte, key bccsp.Key, body []byte) (stri
}
*/
case *ecdsa.PublicKey:
token, err = GenECDSAToken(csp, cert, key, body)
token, err = GenECDSAToken(csp, cert, key, method, uri, body)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -223,10 +225,11 @@ func GenRSAToken(csp bccsp.BCCSP, cert []byte, key []byte, body []byte) (string,
*/

//GenECDSAToken signs the http body and cert with ECDSA using EC private key
func GenECDSAToken(csp bccsp.BCCSP, cert []byte, key bccsp.Key, body []byte) (string, error) {
func GenECDSAToken(csp bccsp.BCCSP, cert []byte, key bccsp.Key, method, uri string, body []byte) (string, error) {
b64body := B64Encode(body)
b64cert := B64Encode(cert)
bodyAndcert := b64body + "." + b64cert
b64uri := B64Encode([]byte(uri))
bodyAndcert := method + "." + b64uri + "." + b64body + "." + b64cert

digest, digestError := csp.Hash([]byte(bodyAndcert), &bccsp.SHAOpts{})
if digestError != nil {
Expand All @@ -250,7 +253,7 @@ func GenECDSAToken(csp bccsp.BCCSP, cert []byte, key bccsp.Key, body []byte) (st

// VerifyToken verifies token signed by either ECDSA or RSA and
// returns the associated user ID
func VerifyToken(csp bccsp.BCCSP, token string, body []byte) (*x509.Certificate, error) {
func VerifyToken(csp bccsp.BCCSP, token string, method, uri string, body []byte) (*x509.Certificate, error) {

if csp == nil {
return nil, errors.New("BCCSP instance is not present")
Expand All @@ -264,7 +267,8 @@ func VerifyToken(csp bccsp.BCCSP, token string, body []byte) (*x509.Certificate,
return nil, errors.WithMessage(err, "Invalid base64 encoded signature in token")
}
b64Body := B64Encode(body)
sigString := b64Body + "." + b64Cert
b64uri := B64Encode([]byte(uri))
sigString := method + "." + b64uri + "." + b64Body + "." + b64Cert

pk2, err := csp.KeyImport(x509Cert, &bccsp.X509PublicKeyImportOpts{Temporary: true})
if err != nil {
Expand Down
36 changes: 23 additions & 13 deletions util/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,34 +60,44 @@ func TestECCreateToken(t *testing.T) {
}
body := []byte("request byte array")

ECtoken, err := CreateToken(bccsp, cert, privKey, body)
ECtoken, err := CreateToken(bccsp, cert, privKey, "GET", "/enroll", body)
if err != nil {
t.Fatalf("CreatToken failed: %s", err)
}

_, err = VerifyToken(bccsp, ECtoken, body)
_, err = VerifyToken(bccsp, ECtoken, "GET", "/enroll", body)
if err != nil {
t.Fatalf("VerifyToken failed: %s", err)
}

_, err = VerifyToken(nil, ECtoken, body)
_, err = VerifyToken(nil, ECtoken, "GET", "/enroll", body)
if err == nil {
t.Fatal("VerifyToken should have failed as no instance of csp is passed")
}

_, err = VerifyToken(bccsp, "", body)
_, err = VerifyToken(bccsp, "", "GET", "/enroll", body)
if err == nil {
t.Fatal("VerifyToken should have failed as no EC Token is passed")
}

_, err = VerifyToken(bccsp, ECtoken, nil)
_, err = VerifyToken(bccsp, ECtoken, "GET", "/enroll", nil)
if err == nil {
t.Fatal("VerifyToken should have failed as no EC Token is passed")
t.Fatal("VerifyToken should have failed as no body is passed")
}

_, err = VerifyToken(bccsp, ECtoken, "POST", "/enroll", nil)
if err == nil {
t.Fatal("VerifyToken should have failed as method was tampered")
}

_, err = VerifyToken(bccsp, ECtoken, "GET", "/affiliations", nil)
if err == nil {
t.Fatal("VerifyToken should have failed as path was tampered")
}

verifiedByte := []byte("TEST")
body = append(body, verifiedByte[0])
_, err = VerifyToken(bccsp, ECtoken, body)
_, err = VerifyToken(bccsp, ECtoken, "GET", "/enroll", body)
if err == nil {
t.Fatal("VerifyToken should have failed as body was tampered")
}
Expand All @@ -96,7 +106,7 @@ func TestECCreateToken(t *testing.T) {
if skierror != nil {
t.Fatalf("SKI File Read failed with error : %s", skierror)
}
ECtoken, err = CreateToken(bccsp, ski, privKey, body)
ECtoken, err = CreateToken(bccsp, ski, privKey, "GET", "/enroll", body)
if (err == nil) || (ECtoken != "") {
t.Fatal("CreatToken should have failed as certificate passed is not correct")
}
Expand Down Expand Up @@ -180,7 +190,7 @@ func TestCreateTokenDiffKey(t *testing.T) {
bccsp := GetDefaultBCCSP()
privKey, _ := ImportBCCSPKeyFromPEM(getPath("rsa-key.pem"), bccsp, true)
body := []byte("request byte array")
_, err := CreateToken(bccsp, cert, privKey, body)
_, err := CreateToken(bccsp, cert, privKey, "POST", "/enroll", body)
if err == nil {
t.Fatalf("TestCreateTokenDiffKey passed but should have failed")
}
Expand All @@ -207,7 +217,7 @@ func TestEmptyToken(t *testing.T) {
body := []byte("request byte array")

csp := factory.GetDefault()
_, err := VerifyToken(csp, "", body)
_, err := VerifyToken(csp, "", "POST", "/enroll", body)
if err == nil {
t.Fatalf("TestEmptyToken passed but should have failed")
}
Expand All @@ -218,7 +228,7 @@ func TestEmptyCert(t *testing.T) {
body := []byte("request byte array")

csp := factory.GetDefault()
_, err := CreateToken(csp, cert, nil, body)
_, err := CreateToken(csp, cert, nil, "POST", "/enroll", body)
if err == nil {
t.Fatalf("TestEmptyCert passed but should have failed")
}
Expand All @@ -228,7 +238,7 @@ func TestEmptyKey(t *testing.T) {
bccsp := GetDefaultBCCSP()
privKey, _ := ImportBCCSPKeyFromPEM(getPath("ec-key.pem"), bccsp, true)
body := []byte("request byte array")
_, err := CreateToken(bccsp, []byte(""), privKey, body)
_, err := CreateToken(bccsp, []byte(""), privKey, "POST", "/enroll", body)
if err == nil {
t.Fatalf("TestEmptyKey passed but should have failed")
}
Expand All @@ -238,7 +248,7 @@ func TestEmptyBody(t *testing.T) {
bccsp := GetDefaultBCCSP()
privKey, _ := ImportBCCSPKeyFromPEM(getPath("ec-key.pem"), bccsp, true)
cert, _ := ioutil.ReadFile(getPath("ec.pem"))
_, err := CreateToken(bccsp, cert, privKey, []byte(""))
_, err := CreateToken(bccsp, cert, privKey, "POST", "/enroll", []byte(""))
if err != nil {
t.Fatalf("CreateToken failed: %s", err)
}
Expand Down

0 comments on commit 02858a7

Please sign in to comment.