Skip to content

Commit

Permalink
Merge pull request #1 from iris-platform/master
Browse files Browse the repository at this point in the history
moving changes from base
  • Loading branch information
hbellur committed Jan 18, 2018
2 parents aff30ac + 59993fb commit ee80f24
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 105 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Expand Up @@ -8,7 +8,7 @@ RUN apt-get -y install git

# Install Stable Go
WORKDIR /opt
RUN curl -O https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz && tar -C /usr/local -xzf /opt/go1.8.3.linux-amd64.tar.gz
RUN curl -O https://storage.googleapis.com/golang/go1.9.2.linux-amd64.tar.gz && tar -C /usr/local -xzf /opt/go1.9.2.linux-amd64.tar.gz
ENV PATH /usr/local/go/bin:/usr/local/bin:$PATH
ENV GOPATH /usr/local/notification_manager
ENV GOBIN $GOPATH/bin
Expand Down
30 changes: 15 additions & 15 deletions README.md
@@ -1,15 +1,15 @@
# vesper
SHAKEN based signing and validation server

# APIs
## APIs

# POST /stir/v1/signing
### POST /stir/v1/signing

## HTTP Response
#### HTTP Response

### Success
##### Success

#### 200 OK
###### 200 OK

Example
```
Expand All @@ -20,9 +20,9 @@ Example
}
```

### Unsuccessful
##### Unsuccessful

#### 400
###### 400

Example
```
Expand Down Expand Up @@ -62,7 +62,7 @@ Example
| VESPER-0024 | dest tn in request payload is not an array |
| VESPER-0025 | dest field in request payload MUST be a JSON object |

#### 500
###### 500

Example
```
Expand All @@ -81,13 +81,13 @@ Example
| VESPER-0052 | error in signing request |


# POST /stir/v1/verification
### POST /stir/v1/verification

## HTTP Response
#### HTTP Response

### Success
##### Success

#### 200
###### 200

Example
```
Expand Down Expand Up @@ -129,9 +129,9 @@ Example
}
```

### Unsuccessful
##### Unsuccessful

#### 400
###### 400

Example
```
Expand Down Expand Up @@ -180,7 +180,7 @@ Example
| VESPER-0133 | typ field value in JWT header is not a string |
| VESPER-0134 | x5u field value in JWT header is not a string |

#### 500
###### 500

Example
```
Expand Down
159 changes: 83 additions & 76 deletions src/vesper/common.go
Expand Up @@ -8,99 +8,41 @@ import (
"reflect"
)

func validatePayload(r map[string]interface{}, traceID, clientIP string) (string, uint64, []string, string, error) {
func validatePayload(r map[string]interface{}, traceID, clientIP string) (map[string]interface{}, string, uint64, []string, string, error) {
var attest, origid, origTN string
var iat uint64
var destTNs []string
orderedMap := make(map[string]interface{}) // this is a copy of the map passed in input except the keys are ordered

if !reflect.ValueOf(r["attest"]).IsValid() || !reflect.ValueOf(r["dest"]).IsValid() || !reflect.ValueOf(r["iat"]).IsValid() || !reflect.ValueOf(r["orig"]).IsValid() || !reflect.ValueOf(r["origid"]).IsValid() {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=one or more of the require fields missing in request payload (%+v)", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0003", fmt.Errorf("one or more of the require fields missing in request payload")
return orderedMap, origTN, iat, destTNs, "VESPER-0003", fmt.Errorf("one or more of the require fields missing in request payload")
}
// request payload should not contain more than the expected fields
if len(r) != 5 {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=request payload (%+v) has more than expected fields", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0004", fmt.Errorf("request payload has more than expected fields")
return orderedMap, origTN, iat, destTNs, "VESPER-0004", fmt.Errorf("request payload has more than expected fields")
}

// attest ...
switch reflect.TypeOf(r["attest"]).Kind() {
case reflect.String:
attest = reflect.ValueOf(r["attest"]).String()
if len(strings.TrimSpace(attest)) == 0 {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=attest field in request payload (%+v) is an empty string", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0005", fmt.Errorf("attest field in request payload is an empty string")
return orderedMap, origTN, iat, destTNs, "VESPER-0005", fmt.Errorf("attest field in request payload is an empty string")
}
switch attest {
case "A", "B", "C":
// as per SHAKEN SPEC
default :
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=attest value in request payload (%+v) is not as per SHAKEN spec", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0006", fmt.Errorf("attest field in request payload is not as per SHAKEN spec")
return orderedMap, origTN, iat, destTNs, "VESPER-0006", fmt.Errorf("attest field in request payload is not as per SHAKEN spec")
}
orderedMap["attest"] = r["attest"]
default:
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=attest field in request payload (%+v) MUST be a string", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0007", fmt.Errorf("attest field in request payload MUST be a string")
}

// iat ...
switch reflect.TypeOf(r["iat"]).Kind() {
case reflect.Float64:
iat = uint64(reflect.ValueOf(r["iat"]).Float())
if iat == 0 {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=iat value in request payload is 0", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0008", fmt.Errorf("iat value in request payload is 0")
}
default:
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=iat field in request payload (%+v) MUST be a number", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0009", fmt.Errorf("iat field in request payload MUST be a number")
}

// origid ...
switch reflect.TypeOf(r["origid"]).Kind() {
case reflect.String:
origid = reflect.ValueOf(r["origid"]).String()
if len(strings.TrimSpace(origid)) == 0 {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=origid field in request payload (%+v) is an empty string", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0010", fmt.Errorf("origid field in request payload is an empty string")
}
default:
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=origid field in request payload (%+v) MUST be a string", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0011", fmt.Errorf("origid field in request payload MUST be a string")
}

// orig ...
switch reflect.TypeOf(r["orig"]).Kind() {
case reflect.Map:
origKeys := reflect.ValueOf(r["orig"]).MapKeys()
switch {
case len(origKeys) == 0 :
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=orig in request payload (%+v) is an empty object", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0012", fmt.Errorf("orig in request payload is an empty object")
case len(origKeys) > 1 :
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=orig in request payload (%+v) should contain only one field", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0013", fmt.Errorf("orig in request payload should contain only one field")
default:
// field should be "tn" only
if origKeys[0].String() != "tn" {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=orig in request payload (%+v) does not contain field \"tn\"", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0014", fmt.Errorf("orig in request payload does not contain field \"tn\"")
}
// validate "tn" value is of type string and is not an empty string
_, ok := r["orig"].(map[string]interface{})["tn"].(string)
if !ok {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=orig tn in request payload (%+v) is not of type string", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0015", fmt.Errorf("orig tn in request payload is not of type string")
}
origTN = r["orig"].(map[string]interface{})["tn"].(string)
if len(strings.TrimSpace(origTN)) == 0 {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=orig tn in request payload (%+v) is an empty string", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0016", fmt.Errorf("orig tn in request payload is an empty string")
}
}
default:
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=orig field in request payload (%+v) MUST be a JSON object", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0017", fmt.Errorf("orig field in request payload MUST be a JSON object")
return orderedMap, origTN, iat, destTNs, "VESPER-0007", fmt.Errorf("attest field in request payload MUST be a string")
}

// dest ...
Expand All @@ -110,15 +52,15 @@ func validatePayload(r map[string]interface{}, traceID, clientIP string) (string
switch {
case len(destKeys) == 0 :
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=dest in request payload (%+v) is an empty object", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0018", fmt.Errorf("dest in request payload is an empty object")
return orderedMap, origTN, iat, destTNs, "VESPER-0018", fmt.Errorf("dest in request payload is an empty object")
case len(destKeys) > 1 :
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=dest in request payload (%+v) should contain only one field", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0019", fmt.Errorf("dest in request payload should contain only one field")
return orderedMap, origTN, iat, destTNs, "VESPER-0019", fmt.Errorf("dest in request payload should contain only one field")
default:
// field should be "tn" only
if destKeys[0].String() != "tn" {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=dest in request payload (%+v) does not contain field \"tn\"", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0020", fmt.Errorf("dest in request payload does not contain field \"tn\"")
return orderedMap, origTN, iat, destTNs, "VESPER-0020", fmt.Errorf("dest in request payload does not contain field \"tn\"")
}
// validate "tn" value is of type string and is not an empty string
switch reflect.TypeOf(r["dest"].(map[string]interface{})["tn"]).Kind() {
Expand All @@ -127,31 +69,96 @@ func validatePayload(r map[string]interface{}, traceID, clientIP string) (string
dt := reflect.ValueOf(r["dest"].(map[string]interface{})["tn"])
if dt.Len() == 0 {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=dest tn in request payload (%+v) is an empty array", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0021", fmt.Errorf("dest tn in request payload is an empty array")
return orderedMap, origTN, iat, destTNs, "VESPER-0021", fmt.Errorf("dest tn in request payload is an empty array")
}
// contains empty string
for i := 0; i < dt.Len(); i++ {
tn := dt.Index(i).Elem()
if tn.Kind() != reflect.String {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=one or more dest tns in request payload (%+v) is not a string", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0022", fmt.Errorf("one or more dest tns in request payload is not a string")
return orderedMap, origTN, iat, destTNs, "VESPER-0022", fmt.Errorf("one or more dest tns in request payload is not a string")
} else {
if len(strings.TrimSpace(tn.String())) == 0 {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=one or more dest tns in request payload (%+v) is an empty string", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0023", fmt.Errorf("one or more dest tns in request payload is an empty string")
return orderedMap, origTN, iat, destTNs, "VESPER-0023", fmt.Errorf("one or more dest tns in request payload is an empty string")
}
// append desl TNs here
destTNs = append(destTNs, tn.String())
}
}
default:
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=dest tn in request payload (%+v) is not an array", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0024", fmt.Errorf("dest tn in request payload is not an array")
return orderedMap, origTN, iat, destTNs, "VESPER-0024", fmt.Errorf("dest tn in request payload is not an array")
}
orderedMap["dest"] = r["dest"]
}
default:
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=dest field in request payload (%+v) MUST be a JSON object", traceID, clientIP, r);
return origTN, iat, destTNs, "VESPER-0025", fmt.Errorf("dest field in request payload MUST be a JSON object")
return orderedMap, origTN, iat, destTNs, "VESPER-0025", fmt.Errorf("dest field in request payload MUST be a JSON object")
}
return origTN, iat, destTNs, "", nil

// iat ...
switch reflect.TypeOf(r["iat"]).Kind() {
case reflect.Float64:
iat = uint64(reflect.ValueOf(r["iat"]).Float())
if iat == 0 {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=iat value in request payload is 0", traceID, clientIP, r);
return orderedMap, origTN, iat, destTNs, "VESPER-0008", fmt.Errorf("iat value in request payload is 0")
}
orderedMap["iat"] = r["iat"]
default:
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=iat field in request payload (%+v) MUST be a number", traceID, clientIP, r);
return orderedMap, origTN, iat, destTNs, "VESPER-0009", fmt.Errorf("iat field in request payload MUST be a number")
}

// orig ...
switch reflect.TypeOf(r["orig"]).Kind() {
case reflect.Map:
origKeys := reflect.ValueOf(r["orig"]).MapKeys()
switch {
case len(origKeys) == 0 :
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=orig in request payload (%+v) is an empty object", traceID, clientIP, r);
return orderedMap, origTN, iat, destTNs, "VESPER-0012", fmt.Errorf("orig in request payload is an empty object")
case len(origKeys) > 1 :
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=orig in request payload (%+v) should contain only one field", traceID, clientIP, r);
return orderedMap, origTN, iat, destTNs, "VESPER-0013", fmt.Errorf("orig in request payload should contain only one field")
default:
// field should be "tn" only
if origKeys[0].String() != "tn" {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=orig in request payload (%+v) does not contain field \"tn\"", traceID, clientIP, r);
return orderedMap, origTN, iat, destTNs, "VESPER-0014", fmt.Errorf("orig in request payload does not contain field \"tn\"")
}
// validate "tn" value is of type string and is not an empty string
_, ok := r["orig"].(map[string]interface{})["tn"].(string)
if !ok {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=orig tn in request payload (%+v) is not of type string", traceID, clientIP, r);
return orderedMap, origTN, iat, destTNs, "VESPER-0015", fmt.Errorf("orig tn in request payload is not of type string")
}
origTN = r["orig"].(map[string]interface{})["tn"].(string)
if len(strings.TrimSpace(origTN)) == 0 {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=orig tn in request payload (%+v) is an empty string", traceID, clientIP, r);
return orderedMap, origTN, iat, destTNs, "VESPER-0016", fmt.Errorf("orig tn in request payload is an empty string")
}
}
orderedMap["orig"] = r["orig"]
default:
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=orig field in request payload (%+v) MUST be a JSON object", traceID, clientIP, r);
return orderedMap, origTN, iat, destTNs, "VESPER-0017", fmt.Errorf("orig field in request payload MUST be a JSON object")
}

// origid ...
switch reflect.TypeOf(r["origid"]).Kind() {
case reflect.String:
origid = reflect.ValueOf(r["origid"]).String()
if len(strings.TrimSpace(origid)) == 0 {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=origid field in request payload (%+v) is an empty string", traceID, clientIP, r);
return orderedMap, origTN, iat, destTNs, "VESPER-0010", fmt.Errorf("origid field in request payload is an empty string")
}
orderedMap["origid"] = r["origid"]
default:
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=validatePayload, Message=origid field in request payload (%+v) MUST be a string", traceID, clientIP, r);
return orderedMap, origTN, iat, destTNs, "VESPER-0011", fmt.Errorf("origid field in request payload MUST be a string")
}

return orderedMap, origTN, iat, destTNs, "", nil
}
3 changes: 1 addition & 2 deletions src/vesper/shaken.go
Expand Up @@ -19,8 +19,8 @@ import (
// ShakenHdr - structure that holds JWT header
type ShakenHdr struct {
Alg string `json:"alg"`
Typ string `json:"typ"`
Ppt string `json:"ppt"`
Typ string `json:"typ"`
X5u string `json:"x5u"`
}

Expand Down Expand Up @@ -125,7 +125,6 @@ func createSignature(header, claims []byte) (string, string, error) {
// alg = ES256
pvtkey, err := x509.ParseECPrivateKey(block.Bytes)
if err == nil {
logInfo("Got here")
canonical_string, sig, err := encodeEC(header, claims, pvtkey)
if err == nil {
return canonical_string, sig, nil
Expand Down
21 changes: 11 additions & 10 deletions src/vesper/sign.go
Expand Up @@ -47,19 +47,20 @@ func signRequest(response http.ResponseWriter, request *http.Request, _ httprout
json.NewEncoder(response).Encode(jsonErr)
return
default:
// err == nil
_, _, _, errCode, err := validatePayload(r, traceID, clientIP)
if err != nil {
response.WriteHeader(http.StatusBadRequest)
jsonErr := SResponse{SigningResponse : ErrorBlob{ReasonCode: errCode, ReasonString: err.Error()}}
json.NewEncoder(response).Encode(jsonErr)
return
}
// err == nil. continue
}
orderedMap, _, _, _, errCode, err := validatePayload(r, traceID, clientIP)
if err != nil {
response.WriteHeader(http.StatusBadRequest)
jsonErr := SResponse{SigningResponse : ErrorBlob{ReasonCode: errCode, ReasonString: err.Error()}}
json.NewEncoder(response).Encode(jsonErr)
return
}

logInfo("Type=vespersignRequest, TraceID=%v, Module=signRequest, Message=%+v", traceID, r)

// at this point, the input has been validated
hdr := ShakenHdr{ Alg: "ES256", Typ: "passport", Ppt: "shaken", X5u: config.Authentication["x5u"].(string)}
hdr := ShakenHdr{ Alg: "ES256", Ppt: "shaken", Typ: "passport", X5u: config.Authentication["x5u"].(string)}
hdrBytes, err := json.Marshal(hdr)
if err != nil {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=signRequest, Message=error in converting header to byte array : %v", traceID, clientIP, err);
Expand All @@ -68,7 +69,7 @@ func signRequest(response http.ResponseWriter, request *http.Request, _ httprout
json.NewEncoder(response).Encode(jsonErr)
return
}
claimsBytes, _ := json.Marshal(r)
claimsBytes, _ := json.Marshal(orderedMap)
if err != nil {
logError("Type=vesperRequestPayload, TraceID=%v, ClientIP=%v, Module=signRequest, Message=error in converting claims to byte array : %v", traceID, clientIP, err);
response.WriteHeader(http.StatusInternalServerError)
Expand Down

1 comment on commit ee80f24

@hbellur
Copy link
Collaborator Author

@hbellur hbellur commented on ee80f24 Feb 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging to latest changes

Please sign in to comment.