Skip to content

Commit

Permalink
cert: Add AS certificate (#2936)
Browse files Browse the repository at this point in the history
This PR adds the AS certificate with parsing and validation.

contributes to #2853
  • Loading branch information
oncilla authored Jul 30, 2019
1 parent ecaa736 commit a0058c7
Show file tree
Hide file tree
Showing 6 changed files with 636 additions and 2 deletions.
7 changes: 6 additions & 1 deletion go/lib/scrypto/cert/v2/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "go_default_library",
srcs = ["base.go"],
srcs = [
"as.go",
"base.go",
],
importpath = "github.com/scionproto/scion/go/lib/scrypto/cert/v2",
visibility = ["//visibility:public"],
deps = [
Expand All @@ -15,6 +18,8 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"as_json_test.go",
"as_test.go",
"base_json_test.go",
"base_test.go",
],
Expand Down
151 changes: 151 additions & 0 deletions go/lib/scrypto/cert/v2/as.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// Copyright 2019 Anapaya Systems
//
// 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 cert

import (
"bytes"
"encoding/json"
"errors"

"github.com/scionproto/scion/go/lib/addr"
"github.com/scionproto/scion/go/lib/common"
"github.com/scionproto/scion/go/lib/scrypto"
)

const (
// IssuerDifferentISD indicates that the issuing AS is in a different ISD.
IssuerDifferentISD = "issuing AS in different ISD"
// InvalidCertificateType indicates the certificate type is invalid.
InvalidCertificateType = "invalid certificate type"
)

var (
// ErrIssuerIANotSet indicates the issuer IA is not set.
ErrIssuerIANotSet = errors.New("issuer IA not set")
// ErrIssuerCertificateVersionNotSet indicates the issuer certificate version is not set.
ErrIssuerCertificateVersionNotSet = errors.New("issuer certificate version not set")
)

// AS is the AS certificate.
type AS struct {
Base
// Issuer holds the identifiers of the issuing issuer certificate.
Issuer IssuerCertID `json:"Issuer"`
// CertificateType ensures the correct certificate type when marshalling.
CertificateType TypeAS `json:"CertificateType"`
}

// Validate checks that the certificate is in a valid format.
func (c *AS) Validate() error {
if err := c.Base.Validate(); err != nil {
return err
}
if err := c.validateKeys(false); err != nil {
return err
}
if c.Subject.I != c.Issuer.IA.I {
return common.NewBasicError(IssuerDifferentISD, nil,
"subject", c.Subject, "issuer", c.Issuer.IA)
}
return nil
}

// UnmarshalJSON checks that all fields are set.
func (c *AS) UnmarshalJSON(b []byte) error {
var cAlias asAlias
dec := json.NewDecoder(bytes.NewReader(b))
dec.DisallowUnknownFields()
if err := dec.Decode(&cAlias); err != nil {
return err
}
if err := cAlias.checkAllSet(); err != nil {
return err
}
*c = AS{
Base: cAlias.Base,
Issuer: *cAlias.Issuer,
CertificateType: *cAlias.CertificateType,
}
return nil
}

type asAlias struct {
Base
Issuer *IssuerCertID `json:"Issuer"`
CertificateType *TypeAS `json:"CertificateType"`
}

func (c *asAlias) checkAllSet() error {
if err := c.Base.checkAllSet(); err != nil {
return err
}
switch {
case c.Issuer == nil:
return ErrIssuerNotSet
case c.CertificateType == nil:
return ErrCertificateTypeNotSet
}
return nil
}

// issuerCertIDAlias is necessary to avoid an infinite recursion when unmarshalling.
type issuerCertIDAlias IssuerCertID

// IssuerCertID identifies the issuer certificate that authenticates the AS certificate.
type IssuerCertID struct {
// IA is the subject of the issuing issuer certificate.
IA addr.IA `json:"IA"`
// CertificateVersion is the version of the issuing issuer certificate.
CertificateVersion scrypto.Version `json:"CertificateVersion"`
}

// UnmarshalJSON checks that all fields are set.
func (i *IssuerCertID) UnmarshalJSON(b []byte) error {
dec := json.NewDecoder(bytes.NewReader(b))
dec.DisallowUnknownFields()
if err := dec.Decode((*issuerCertIDAlias)(i)); err != nil {
return err
}
return i.checkAllSet()
}

func (i *IssuerCertID) checkAllSet() error {
switch {
case i.IA.IsWildcard():
return ErrIssuerIANotSet
case i.CertificateVersion == 0:
return ErrIssuerCertificateVersionNotSet
}
return nil
}

const TypeASJSON = "AS"

// TypeAS indicates an AS certificate.
type TypeAS struct{}

// UnmarshalText checks that the certificate type matches.
func (TypeAS) UnmarshalText(b []byte) error {
if TypeASJSON != string(b) {
return common.NewBasicError(InvalidCertificateType, nil,
"expected", TypeASJSON, "actual", string(b))
}
return nil
}

// MarshalText returns the AS certificate type.
func (TypeAS) MarshalText() ([]byte, error) {
return []byte(TypeASJSON), nil
}
Loading

0 comments on commit a0058c7

Please sign in to comment.