Skip to content

Commit

Permalink
updated pki
Browse files Browse the repository at this point in the history
Signed-off-by: Patrick Zheng <[email protected]>
  • Loading branch information
Two-Hearts committed Jan 29, 2024
1 parent 50ddae5 commit 55fba00
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 32 deletions.
125 changes: 96 additions & 29 deletions pki/pki.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,98 @@
// limitations under the License.

// Package pki contains certificate management protocol structures
// defined in RFC 2510.
// defined in RFC 3161.
package pki

import "encoding/asn1"
import (
"encoding/asn1"
"errors"
)

// ErrUnknownStatus is used when PKIStatus is not supported
var ErrUnknownStatus = errors.New("unknown PKIStatus")

// ErrUnknownFailureInfo is used when PKIFailureInfo is not supported or does
// not exists
var ErrUnknownFailureInfo = errors.New("unknown PKIFailureInfo")

// Status is PKIStatus defined in RFC 3161 2.4.2.
type Status int

// PKIStatus is defined in RFC 2510 3.2.3.
const (
StatusGranted = 0 // you got exactly what you asked for
StatusGrantedWithMods = 1 // you got something like what you asked for
StatusRejection = 2 // you don't get it, more information elsewhere in the message
StatusWaiting = 3 // the request body part has not yet been processed, expect to hear more later
StatusRevocationWarning = 4 // this message contains a warning that a revocation is imminent
StatusRevocationNotification = 5 // notification that a revocation has occurred
StatusKeyUpdateWarning = 6 // update already done for the oldCertId specified in the key update request message
StatusGranted Status = 0 // you got exactly what you asked for
StatusGrantedWithMods Status = 1 // you got something like what you asked for
StatusRejection Status = 2 // you don't get it, more information elsewhere in the message
StatusWaiting Status = 3 // the request body part has not yet been processed, expect to hear more later
StatusRevocationWarning Status = 4 // this message contains a warning that a revocation is imminent
StatusRevocationNotification Status = 5 // notification that a revocation has occurred
)

// PKIFailureInfo is defined in RFC 2510 3.2.3 and RFC 3161 2.4.2.
// Statuses is an array of supported PKIStatus
var Statuses = []Status{StatusGranted, StatusGrantedWithMods, StatusRejection, StatusWaiting, StatusRevocationWarning, StatusRevocationNotification}

// String converts Status to string
func (ps Status) String() string {
switch ps {
case StatusGranted:
return "granted"
case StatusGrantedWithMods:
return "granted with modifications"
case StatusRejection:
return "rejected"
case StatusWaiting:
return "the request body part has not yet been processed, expect to hear more later"
case StatusRevocationWarning:
return "warning: a revocation is imminent"
case StatusRevocationNotification:
return "a revocation has occurred"
default:
return "unknown PKIStatus"
}
}

// FailureInfo is PKIFailureInfo defined in RFC 3161 2.4.2.
type FailureInfo int

const (
FailureInfoBadAlg = 0 // unrecognized or unsupported Algorithm Identifier
FailureInfoBadMessageCheck = 1 // integrity check failed (e.g., signature did not verify)
FailureInfoBadRequest = 2 // transaction not permitted or supported
FailureInfoBadTime = 3 // messageTime was not sufficiently close to the system time, as defined by local policy
FailureInfoBadCertID = 4 // no certificate could be found matching the provided criteria
FailureInfoBadDataFormat = 5 // the data submitted has the wrong format
FailureInfoWrongAuthority = 6 // the authority indicated in the request is different from the one creating the response token
FailureInfoIncorrectData = 7 // the requester's data is incorrect (used for notary services)
FailureInfoMissingTimeStamp = 8 // the timestamp is missing but should be there (by policy)
FailureInfoBadPOP = 9 // the proof-of-possession failed
FailureInfoTimeNotAvailable = 14 // the TSA's time source is not available
FailureInfoUnacceptedPolicy = 15 // the requested TSA policy is not supported by the TSA.
FailureInfoUnacceptedExtension = 16 // the requested extension is not supported by the TSA.
FailureInfoAddInfoNotAvailable = 17 // the additional information requested could not be understood or is not available
FailureInfoSystemFailure = 25 // the request cannot be handled due to system failure
FailureInfoBadAlg FailureInfo = 0 // unrecognized or unsupported Algorithm Identifier
FailureInfoBadRequest FailureInfo = 2 // transaction not permitted or supported
FailureInfoBadDataFormat FailureInfo = 5 // the data submitted has the wrong format
FailureInfoTimeNotAvailable FailureInfo = 14 // the TSA's time source is not available
FailureInfoUnacceptedPolicy FailureInfo = 15 // the requested TSA policy is not supported by the TSA.
FailureInfoUnacceptedExtension FailureInfo = 16 // the requested extension is not supported by the TSA.
FailureInfoAddInfoNotAvailable FailureInfo = 17 // the additional information requested could not be understood or is not available
FailureInfoSystemFailure FailureInfo = 25 // the request cannot be handled due to system failure
)

// FailureInfos is an array of supported PKIFailureInfo
var FailureInfos = []FailureInfo{FailureInfoBadAlg, FailureInfoBadRequest, FailureInfoBadDataFormat, FailureInfoTimeNotAvailable,
FailureInfoUnacceptedPolicy, FailureInfoUnacceptedExtension, FailureInfoAddInfoNotAvailable, FailureInfoSystemFailure}

// String converts FailureInfo to string
func (pf FailureInfo) String() string {
switch pf {
case FailureInfoBadAlg:
return "unrecognized or unsupported Algorithm Identifier"
case FailureInfoBadRequest:
return "transaction not permitted or supported"
case FailureInfoBadDataFormat:
return "the data submitted has the wrong format"
case FailureInfoTimeNotAvailable:
return "the TSA's time source is not available"
case FailureInfoUnacceptedPolicy:
return "the requested TSA policy is not supported by the TSA"
case FailureInfoUnacceptedExtension:
return "the requested extension is not supported by the TSA"
case FailureInfoAddInfoNotAvailable:
return "the additional information requested could not be understood or is not available"
case FailureInfoSystemFailure:
return "the request cannot be handled due to system failure"
default:
return "unknown PKIFailureInfo"
}
}

// StatusInfo contains status codes and failure information for PKI messages.
//
// PKIStatusInfo ::= SEQUENCE {
Expand All @@ -57,10 +114,20 @@ const (
// PKIStatus ::= INTEGER
// PKIFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String
// PKIFailureInfo ::= BIT STRING
// Reference: RFC 2510 3.2.3 Status codes and Failure Information for
// PKI messages.
//
// Reference: RFC 3161 2.4.2
type StatusInfo struct {
Status int
Status Status
StatusString []string `asn1:"optional,utf8"`
FailInfo asn1.BitString `asn1:"optional"`
}

// ParseFailInfo parses the FailInfo field of a PKIStatusInfo to PKIFailureInfo
func (psi StatusInfo) ParseFailInfo() (FailureInfo, error) {
for _, pfi := range FailureInfos {
if psi.FailInfo.At(int(pfi)) != 0 {
return pfi, nil
}
}
return 0, ErrUnknownFailureInfo
}
98 changes: 98 additions & 0 deletions pki/pki_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright The Notary Project Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package pki

import (
"encoding/asn1"
"errors"
"testing"
)

func TestParseFailInfo(t *testing.T) {
statusInfo := StatusInfo{
Status: StatusGranted,
}
_, err := statusInfo.ParseFailInfo()
if !errors.Is(err, ErrUnknownFailureInfo) {
t.Fatalf("error should be ErrUnknownFailureInfo, but got %s", err)
}

statusInfo = StatusInfo{
Status: StatusRejection,
FailInfo: asn1.BitString{
Bytes: []byte{0x01},
BitLength: 1,
},
}
_, err = statusInfo.ParseFailInfo()
if !errors.Is(err, ErrUnknownFailureInfo) {
t.Fatalf("error should be ErrUnknownFailureInfo, but got %s", err)
}

statusInfo = StatusInfo{
Status: StatusRejection,
FailInfo: asn1.BitString{
Bytes: []byte{0x80},
BitLength: 1,
},
}
failInfo, err := statusInfo.ParseFailInfo()
if err != nil || failInfo != FailureInfoBadAlg {
t.Fatalf("expected %v, but got %v", FailureInfoBadAlg, failInfo)
}
}

func TestStatusString(t *testing.T) {
testData := []string{
"granted",
"granted with modifications",
"rejected",
"the request body part has not yet been processed, expect to hear more later",
"warning: a revocation is imminent",
"a revocation has occurred",
}
for idx, s := range Statuses {
if s.String() != testData[idx] {
t.Fatalf("expected %s, but got %s", s.String(), testData[idx])
}
}

unknown := Status(6)
if unknown.String() != "unknown PKIStatus" {
t.Fatalf("expected %s, but got %s", "unknown PKIStatus", unknown.String())
}
}

func TestFailureInfoString(t *testing.T) {
testData := []string{
"unrecognized or unsupported Algorithm Identifier",
"transaction not permitted or supported",
"the data submitted has the wrong format",
"the TSA's time source is not available",
"the requested TSA policy is not supported by the TSA",
"the requested extension is not supported by the TSA",
"the additional information requested could not be understood or is not available",
"the request cannot be handled due to system failure",
}
for idx, f := range FailureInfos {
if f.String() != testData[idx] {
t.Fatalf("expected %s, but got %s", f.String(), testData[idx])
}
}

unknown := FailureInfo(1)
if unknown.String() != "unknown PKIFailureInfo" {
t.Fatalf("expected %s, but got %s", "unknown PKIFailureInfo", unknown.String())
}
}
6 changes: 5 additions & 1 deletion response.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,11 @@ func (r *Response) UnmarshalBinary(data []byte) error {
// Reference: RFC 3161 2.4.2
func (r *Response) ValidateStatus() error {
if r.Status.Status != pki.StatusGranted && r.Status.Status != pki.StatusGrantedWithMods {
return fmt.Errorf("invalid response with status code: %d", r.Status.Status)
failureInfo, err := r.Status.ParseFailInfo()
if err != nil {
return fmt.Errorf("invalid response with status code %d: %s", r.Status.Status, r.Status.Status.String())
}
return fmt.Errorf("invalid response with status code %d: %s. Failure info: %s", r.Status.Status, r.Status.Status.String(), failureInfo)
}
return nil
}
Expand Down
20 changes: 18 additions & 2 deletions response_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package tspclient

import (
"encoding/asn1"
"testing"

"github.com/notaryproject/tspclient-go/pki"
Expand Down Expand Up @@ -52,12 +53,27 @@ func TestValidateStatus(t *testing.T) {
Status: pki.StatusRejection,
},
}
expectedErrMsg := "invalid response with status code: 2"
expectedErrMsg := "invalid response with status code 2: rejected"
err := (&badResponse).ValidateStatus()
if err == nil || err.Error() != expectedErrMsg {
t.Fatalf("expected error %s, but got %v", expectedErrMsg, err)
}

badResponse = Response{
Status: pki.StatusInfo{
Status: pki.StatusRejection,
FailInfo: asn1.BitString{
Bytes: []byte{0x80},
BitLength: 1,
},
},
}
expectedErrMsg = "invalid response with status code 2: rejected. Failure info: unrecognized or unsupported Algorithm Identifier"
err = (&badResponse).ValidateStatus()
if err == nil || err.Error() != expectedErrMsg {
t.Fatalf("expected error %s, but got %v", expectedErrMsg, err)
}

validResponse := Response{
Status: pki.StatusInfo{
Status: pki.StatusGranted,
Expand All @@ -75,7 +91,7 @@ func TestSignedToken(t *testing.T) {
Status: pki.StatusRejection,
},
}
expectedErrMsg := "invalid response with status code: 2"
expectedErrMsg := "invalid response with status code 2: rejected"
_, err := (&badResponse).SignedToken()
if err == nil || err.Error() != expectedErrMsg {
t.Fatalf("expected error %s, but got %v", expectedErrMsg, err)
Expand Down

0 comments on commit 55fba00

Please sign in to comment.