207 lines
9.9 KiB
Go
207 lines
9.9 KiB
Go
// Copyright 2021 Contributors to the Parsec project.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package requests
|
|
|
|
import (
|
|
"bytes"
|
|
"reflect"
|
|
|
|
"github.com/pkg/errors"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
const wireHeaderSizeValue uint16 = 30
|
|
const WireHeaderSize uint16 = wireHeaderSizeValue + 6
|
|
|
|
// StatusCode type to represent status codes in response headers
|
|
type StatusCode uint16
|
|
|
|
// StatusCode values for response status codes defined here: https://parallaxsecond.github.io/parsec-book/parsec_client/status_codes.html.
|
|
const (
|
|
// Service Internal Response Status Codes
|
|
StatusSuccess StatusCode = 0 // Operation was a success
|
|
StatusWrongProviderID StatusCode = 1 // Requested provider ID does not match that of the backend
|
|
StatusContentTypeNotSupported StatusCode = 2 // Requested content type is not supported by the backend
|
|
StatusAcceptTypeNotSupported StatusCode = 3 // Requested accept type is not supported by the backend
|
|
StatusWireProtocolVersionNotSupported StatusCode = 4 // Requested version is not supported by the backend
|
|
StatusProviderNotRegistered StatusCode = 5 // No provider registered for the requested provider ID
|
|
StatusProviderDoesNotExist StatusCode = 6 // No provider defined for requested provider ID
|
|
StatusDeserializingBodyFailed StatusCode = 7 // Failed to deserialize the body of the message
|
|
StatusSerializingBodyFailed StatusCode = 8 // Failed to serialize the body of the message
|
|
StatusOpcodeDoesNotExist StatusCode = 9 // Requested operation is not defined
|
|
StatusResponseTooLarge StatusCode = 10 // Response size exceeds allowed limits
|
|
StatusAuthenticationError StatusCode = 11 // Authentication failed
|
|
StatusAuthenticatorDoesNotExist StatusCode = 12 // Authenticator not supported
|
|
StatusAuthenticatorNotRegistered StatusCode = 13 // Authenticator not supported
|
|
StatusKeyInfoManagerError StatusCode = 14 // Internal error in the Key Info Manager
|
|
StatusConnectionError StatusCode = 15 // Generic input/output error
|
|
StatusInvalidEncoding StatusCode = 16 // Invalid value for this data type
|
|
StatusInvalidHeader StatusCode = 17 // Constant fields in header are invalid
|
|
StatusWrongProviderUUID StatusCode = 18 // The UUID vector needs to only contain 16 bytes
|
|
StatusNotAuthenticated StatusCode = 19 // Request did not provide a required authentication
|
|
StatusBodySizeExceedsLimit StatusCode = 20 // Request length specified in the header is above defined limit
|
|
StatusAdminOperation StatusCode = 21 // The operation requires admin privilege
|
|
|
|
// PSA Response Status Codes
|
|
|
|
StatusPsaErrorGenericError StatusCode = 1132 // An error occurred that does not correspond to any defined failure cause
|
|
StatusPsaErrorNotPermitted StatusCode = 1133 // The requested action is denied by a policy
|
|
StatusPsaErrorNotSupported StatusCode = 1134 // The requested operation or a parameter is not supported by this implementation
|
|
StatusPsaErrorInvalidArgument StatusCode = 1135 // The parameters passed to the function are invalid
|
|
StatusPsaErrorInvalidHandle StatusCode = 1136 // The key handle is not valid
|
|
StatusPsaErrorBadState StatusCode = 1137 // The requested action cannot be performed in the current state
|
|
StatusPsaErrorBufferTooSmall StatusCode = 1138 // An output buffer is too small
|
|
StatusPsaErrorAlreadyExists StatusCode = 1139 // Asking for an item that already exists
|
|
StatusPsaErrorDoesNotExist StatusCode = 1140 // Asking for an item that doesn't exist
|
|
StatusPsaErrorInsufficientMemory StatusCode = 1141 // There is not enough runtime memory
|
|
StatusPsaErrorInsufficientStorage StatusCode = 1142 // There is not enough persistent storage available
|
|
StatusPsaErrorInssuficientData StatusCode = 1143 // Insufficient data when attempting to read from a resource
|
|
StatusPsaErrorCommunicationFailure StatusCode = 1145 // There was a communication failure inside the implementation
|
|
StatusPsaErrorStorageFailure StatusCode = 1146 // There was a storage failure that may have led to data loss
|
|
StatusPsaErrorHardwareFailure StatusCode = 1147 // A hardware failure was detected
|
|
StatusPsaErrorInsufficientEntropy StatusCode = 1148 // There is not enough entropy to generate random data needed for the requested action
|
|
StatusPsaErrorInvalidSignature StatusCode = 1149 // The signature, MAC or hash is incorrect
|
|
StatusPsaErrorInvalidPadding StatusCode = 1150 // The decrypted padding is incorrect
|
|
StatusPsaErrorCorruptionDetected StatusCode = 1151 // A tampering attempt was detected
|
|
StatusPsaErrorDataCorrupt StatusCode = 1152 // Stored data has been corrupted
|
|
|
|
)
|
|
|
|
func (code StatusCode) IsValid() bool {
|
|
return (code >= StatusSuccess && code <= StatusAdminOperation) || (code >= StatusPsaErrorGenericError && code <= StatusPsaErrorDataCorrupt)
|
|
}
|
|
|
|
// ParseResponse returns a response if it successfully unmarshals the given byte buffer
|
|
func ParseResponse(expectedOpCode OpCode, buf *bytes.Buffer, responseProtoBuf proto.Message) error {
|
|
if buf == nil {
|
|
return errors.Errorf("nil buffer supplied")
|
|
}
|
|
if responseProtoBuf == nil || reflect.ValueOf(responseProtoBuf).IsNil() {
|
|
return errors.Errorf("nil message supplied")
|
|
}
|
|
|
|
hdrBuf := make([]byte, WireHeaderSize)
|
|
_, err := buf.Read(hdrBuf)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to read header")
|
|
}
|
|
wireHeader, err := parseWireHeaderFromBuf(bytes.NewBuffer(hdrBuf))
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to parse header")
|
|
}
|
|
if wireHeader.opCode != expectedOpCode {
|
|
// If we've not got the opcode we expect, don't even try to deserialise the body.
|
|
return errors.Errorf("was expecting response with op code %v, got %v", expectedOpCode, wireHeader.opCode)
|
|
}
|
|
|
|
bodyBuf := make([]byte, wireHeader.bodyLen)
|
|
n, err := buf.Read(bodyBuf)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to read body")
|
|
}
|
|
if uint32(n) != wireHeader.bodyLen {
|
|
return errors.Errorf("body underflow error, expected %v bytes, got %v", wireHeader.bodyLen, n)
|
|
}
|
|
err = proto.Unmarshal(bodyBuf, responseProtoBuf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return wireHeader.Status.ToErr()
|
|
}
|
|
|
|
// ToErr returns nil if the response code is a success, or an appropriate error otherwise.
|
|
//
|
|
//nolint:gocyclo
|
|
func (code StatusCode) ToErr() error {
|
|
switch code {
|
|
case StatusSuccess:
|
|
return nil
|
|
case StatusWrongProviderID:
|
|
return errors.Errorf("wrong provider id")
|
|
case StatusContentTypeNotSupported:
|
|
return errors.Errorf("content type not supported")
|
|
case StatusAcceptTypeNotSupported:
|
|
return errors.Errorf("accept type not supported")
|
|
case StatusWireProtocolVersionNotSupported:
|
|
return errors.Errorf("requested version is not supported by the backend")
|
|
case StatusProviderNotRegistered:
|
|
return errors.Errorf("provider not registered")
|
|
case StatusProviderDoesNotExist:
|
|
return errors.Errorf("provider does not exist")
|
|
case StatusDeserializingBodyFailed:
|
|
return errors.Errorf("deserializing body failed")
|
|
case StatusSerializingBodyFailed:
|
|
return errors.Errorf("serializing body failed")
|
|
case StatusOpcodeDoesNotExist:
|
|
return errors.Errorf("opcode does not exist")
|
|
case StatusResponseTooLarge:
|
|
return errors.Errorf("response too large")
|
|
case StatusAuthenticationError:
|
|
return errors.Errorf("authentication error")
|
|
case StatusAuthenticatorDoesNotExist:
|
|
return errors.Errorf("authentication does not exist")
|
|
case StatusAuthenticatorNotRegistered:
|
|
return errors.Errorf("authentication not registered")
|
|
case StatusKeyInfoManagerError:
|
|
return errors.Errorf("internal error in the Key Info Manager")
|
|
case StatusConnectionError:
|
|
return errors.Errorf("generic input/output error")
|
|
case StatusInvalidEncoding:
|
|
return errors.Errorf("invalid value for this data type")
|
|
case StatusInvalidHeader:
|
|
return errors.Errorf("constant fields in header are invalid")
|
|
case StatusWrongProviderUUID:
|
|
return errors.Errorf("the UUID vector needs to only contain 16 bytes")
|
|
case StatusNotAuthenticated:
|
|
return errors.Errorf("request did not provide a required authentication")
|
|
case StatusBodySizeExceedsLimit:
|
|
return errors.Errorf("request length specified in the header is above defined limit")
|
|
case StatusAdminOperation:
|
|
return errors.Errorf("the operation requires admin privilege")
|
|
|
|
case StatusPsaErrorGenericError:
|
|
return errors.Errorf("generic error")
|
|
case StatusPsaErrorNotPermitted:
|
|
return errors.Errorf("not permitted")
|
|
case StatusPsaErrorNotSupported:
|
|
return errors.Errorf("not supported")
|
|
case StatusPsaErrorInvalidArgument:
|
|
return errors.Errorf("invalid argument")
|
|
case StatusPsaErrorInvalidHandle:
|
|
return errors.Errorf("invalid handle")
|
|
case StatusPsaErrorBadState:
|
|
return errors.Errorf("bad state")
|
|
case StatusPsaErrorBufferTooSmall:
|
|
return errors.Errorf("buffer too small")
|
|
case StatusPsaErrorAlreadyExists:
|
|
return errors.Errorf("already exists")
|
|
case StatusPsaErrorDoesNotExist:
|
|
return errors.Errorf("does not exist")
|
|
case StatusPsaErrorInsufficientMemory:
|
|
return errors.Errorf("insufficient memory")
|
|
case StatusPsaErrorInsufficientStorage:
|
|
return errors.Errorf("insufficient storage")
|
|
case StatusPsaErrorInssuficientData:
|
|
return errors.Errorf("insufficient data")
|
|
case StatusPsaErrorCommunicationFailure:
|
|
return errors.Errorf("communications failure")
|
|
case StatusPsaErrorStorageFailure:
|
|
return errors.Errorf("storage failure")
|
|
case StatusPsaErrorHardwareFailure:
|
|
return errors.Errorf("hardware failure")
|
|
case StatusPsaErrorInsufficientEntropy:
|
|
return errors.Errorf("insufficient entropy")
|
|
case StatusPsaErrorInvalidSignature:
|
|
return errors.Errorf("invalid signature")
|
|
case StatusPsaErrorInvalidPadding:
|
|
return errors.Errorf("invalid padding")
|
|
case StatusPsaErrorCorruptionDetected:
|
|
return errors.Errorf("tampering detected")
|
|
case StatusPsaErrorDataCorrupt:
|
|
return errors.Errorf("stored data has been corrupted")
|
|
}
|
|
return errors.Errorf("unknown error code")
|
|
}
|