Skip to content

Commit

Permalink
fix: update
Browse files Browse the repository at this point in the history
Signed-off-by: Junjie Gao <[email protected]>
  • Loading branch information
JeyJeyGao committed Aug 8, 2024
1 parent f833d94 commit 2c677c1
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 36 deletions.
47 changes: 47 additions & 0 deletions revocation/internal/chain/validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// 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 chain provides the method to validate the certificate chain for a
// specific purpose, including code signing and timestamping.
package chain

import (
"crypto/x509"
"fmt"

"github.com/notaryproject/notation-core-go/revocation/purpose"
"github.com/notaryproject/notation-core-go/revocation/result"
coreX509 "github.com/notaryproject/notation-core-go/x509"
)

// Validate checks the certificate chain for a specific purpose, including
// code signing and timestamping.
func Validate(certChain []*x509.Certificate, certChainPurpose purpose.Purpose) error {
switch certChainPurpose {
case purpose.CodeSigning:
// Since ValidateCodeSigningCertChain is using authentic signing time,
// signing time may be zero.
// Thus, it is better to pass nil here than fail for a cert's NotBefore
// being after zero time
if err := coreX509.ValidateCodeSigningCertChain(certChain, nil); err != nil {
return result.InvalidChainError{Err: err}
}
case purpose.Timestamping:
if err := coreX509.ValidateTimestampingCertChain(certChain); err != nil {
return result.InvalidChainError{Err: err}
}
default:
return result.InvalidChainError{Err: fmt.Errorf("unsupported certificate chain purpose %v", certChainPurpose)}
}
return nil
}
60 changes: 60 additions & 0 deletions revocation/internal/chain/validate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// 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 chain

import (
"crypto/x509"
"testing"

"github.com/notaryproject/notation-core-go/revocation/purpose"
"github.com/notaryproject/notation-core-go/testhelper"
)

func TestValidate(t *testing.T) {
t.Run("unsupported_certificate_chain_purpose", func(t *testing.T) {
certChain := []*x509.Certificate{}
certChainPurpose := purpose.Purpose(-1)
err := Validate(certChain, certChainPurpose)
if err == nil {
t.Errorf("Validate() failed, expected error, got nil")
}
})

t.Run("invalid code signing certificate chain", func(t *testing.T) {
certChain := []*x509.Certificate{}
certChainPurpose := purpose.CodeSigning
err := Validate(certChain, certChainPurpose)
if err == nil {
t.Errorf("Validate() failed, expected error, got nil")
}
})

t.Run("invalid timestamping certificate chain", func(t *testing.T) {
certChain := []*x509.Certificate{}
certChainPurpose := purpose.Timestamping
err := Validate(certChain, certChainPurpose)
if err == nil {
t.Errorf("Validate() failed, expected error, got nil")
}
})

t.Run("valid code signing certificate chain", func(t *testing.T) {
certChain := testhelper.GetRevokableRSAChain(2)
certChainPurpose := purpose.CodeSigning
err := Validate([]*x509.Certificate{certChain[0].Cert, certChain[1].Cert}, certChainPurpose)
if err != nil {
t.Errorf("Validate() failed, expected nil, got %v", err)
}
})
}
4 changes: 2 additions & 2 deletions revocation/internal/crl/crl.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ type Options struct {
// HTTPClient is the HTTP client used to download CRL
HTTPClient *http.Client

// SigningTime is the time when the certificate's private key is
// used to sign the data.
// SigningTime is used to compare with the invalidity date during revocation
// check
SigningTime time.Time
}

Expand Down
29 changes: 4 additions & 25 deletions revocation/internal/ocsp/ocsp.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ import (
"sync"
"time"

"github.com/notaryproject/notation-core-go/revocation/internal/chain"
"github.com/notaryproject/notation-core-go/revocation/purpose"
"github.com/notaryproject/notation-core-go/revocation/result"
coreX509 "github.com/notaryproject/notation-core-go/x509"
"golang.org/x/crypto/ocsp"
)

Expand All @@ -45,9 +45,8 @@ type Options struct {
// values are CodeSigning and Timestamping.
// When not provided, the default value is CodeSigning.
CertChainPurpose purpose.Purpose

SigningTime time.Time
HTTPClient *http.Client
SigningTime time.Time
HTTPClient *http.Client
}

const (
Expand All @@ -67,7 +66,7 @@ func CheckStatus(opts Options) ([]*result.CertRevocationResult, error) {
return nil, result.InvalidChainError{Err: errors.New("chain does not contain any certificates")}
}

if err := ValidateCertificateChain(opts.CertChain, opts.CertChainPurpose); err != nil {
if err := chain.Validate(opts.CertChain, opts.CertChainPurpose); err != nil {
return nil, err
}

Expand Down Expand Up @@ -96,26 +95,6 @@ func CheckStatus(opts Options) ([]*result.CertRevocationResult, error) {
return certResults, nil
}

func ValidateCertificateChain(certChain []*x509.Certificate, certChainPurpose purpose.Purpose) error {
switch certChainPurpose {
case purpose.CodeSigning:
// Since ValidateCodeSigningCertChain is using authentic signing time,
// signing time may be zero.
// Thus, it is better to pass nil here than fail for a cert's NotBefore
// being after zero time
if err := coreX509.ValidateCodeSigningCertChain(certChain, nil); err != nil {
return result.InvalidChainError{Err: err}
}
case purpose.Timestamping:
if err := coreX509.ValidateTimestampingCertChain(certChain); err != nil {
return result.InvalidChainError{Err: err}
}
default:
return result.InvalidChainError{Err: fmt.Errorf("unsupported certificate chain purpose %v", certChainPurpose)}
}
return nil
}

// CertCheckStatus checks the revocation status of a certificate using OCSP
func CertCheckStatus(cert, issuer *x509.Certificate, opts Options) *result.CertRevocationResult {
if !Supported(cert) {
Expand Down
22 changes: 13 additions & 9 deletions revocation/revocation.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"sync"
"time"

"github.com/notaryproject/notation-core-go/revocation/internal/chain"
"github.com/notaryproject/notation-core-go/revocation/internal/crl"
"github.com/notaryproject/notation-core-go/revocation/internal/ocsp"
"github.com/notaryproject/notation-core-go/revocation/purpose"
Expand Down Expand Up @@ -131,32 +132,35 @@ func NewWithOptions(opts Options) (Validator, error) {
// that contain the results and any errors that are encountered during the
// process.
//
// The certificate chain is expected to be in the order of leaf to root.
//
// This function tries OCSP and falls back to CRL when:
// - OCSP is not supported by the certificate
// - OCSP returns an unknown status
//
// When OCSP returns an unknown status, the function will try to check the
// certificate status using CRL and return certificate result with an
// result.OCSPFallbackError.
// NOTE: The certificate chain is expected to be in the order of leaf to root.
func (r *revocation) Validate(certChain []*x509.Certificate, signingTime time.Time) ([]*result.CertRevocationResult, error) {
return r.ValidateContext(context.Background(), ValidateContextOptions{
CertChain: certChain,
AuthenticSigningTime: signingTime,
})
}

// ValidateContext checks the revocation status for a certificate chain using
// OCSP and returns an array of CertRevocationResults that contain the results
// and any errors that are encountered during the process
// ValidateContext checks the revocation status for a certificate chain using OCSP and
// CRL if OCSP is not available. It returns an array of CertRevocationResults
// that contain the results and any errors that are encountered during the
// process.
//
// This function tries OCSP and falls back to CRL when:
// - OCSP is not supported by the certificate
// - OCSP returns an unknown status
//
// NOTE: The certificate chain is expected to be in the order of leaf to root.
func (r *revocation) ValidateContext(ctx context.Context, validateContextOpts ValidateContextOptions) ([]*result.CertRevocationResult, error) {
if len(validateContextOpts.CertChain) == 0 {
return nil, result.InvalidChainError{Err: errors.New("chain does not contain any certificates")}
}
certChain := validateContextOpts.CertChain

if err := ocsp.ValidateCertificateChain(certChain, r.certChainPurpose); err != nil {
if err := chain.Validate(certChain, r.certChainPurpose); err != nil {
return nil, err
}

Expand Down

0 comments on commit 2c677c1

Please sign in to comment.