package pkix
import (
"encoding/asn1"
"encoding/hex"
"fmt"
"math/big"
"time"
)
type AlgorithmIdentifier struct {
Algorithm asn1 .ObjectIdentifier
Parameters asn1 .RawValue `asn1:"optional"`
}
type RDNSequence []RelativeDistinguishedNameSET
var attributeTypeNames = map [string ]string {
"2.5.4.6" : "C" ,
"2.5.4.10" : "O" ,
"2.5.4.11" : "OU" ,
"2.5.4.3" : "CN" ,
"2.5.4.5" : "SERIALNUMBER" ,
"2.5.4.7" : "L" ,
"2.5.4.8" : "ST" ,
"2.5.4.9" : "STREET" ,
"2.5.4.17" : "POSTALCODE" ,
}
func (r RDNSequence ) String () string {
s := ""
for i := 0 ; i < len (r ); i ++ {
rdn := r [len (r )-1 -i ]
if i > 0 {
s += ","
}
for j , tv := range rdn {
if j > 0 {
s += "+"
}
oidString := tv .Type .String ()
typeName , ok := attributeTypeNames [oidString ]
if !ok {
derBytes , err := asn1 .Marshal (tv .Value )
if err == nil {
s += oidString + "=#" + hex .EncodeToString (derBytes )
continue
}
typeName = oidString
}
valueString := fmt .Sprint (tv .Value )
escaped := make ([]rune , 0 , len (valueString ))
for k , c := range valueString {
escape := false
switch c {
case ',' , '+' , '"' , '\\' , '<' , '>' , ';' :
escape = true
case ' ' :
escape = k == 0 || k == len (valueString )-1
case '#' :
escape = k == 0
}
if escape {
escaped = append (escaped , '\\' , c )
} else {
escaped = append (escaped , c )
}
}
s += typeName + "=" + string (escaped )
}
}
return s
}
type RelativeDistinguishedNameSET []AttributeTypeAndValue
type AttributeTypeAndValue struct {
Type asn1 .ObjectIdentifier
Value any
}
type AttributeTypeAndValueSET struct {
Type asn1 .ObjectIdentifier
Value [][]AttributeTypeAndValue `asn1:"set"`
}
type Extension struct {
Id asn1 .ObjectIdentifier
Critical bool `asn1:"optional"`
Value []byte
}
type Name struct {
Country , Organization , OrganizationalUnit []string
Locality , Province []string
StreetAddress , PostalCode []string
SerialNumber , CommonName string
Names []AttributeTypeAndValue
ExtraNames []AttributeTypeAndValue
}
func (n *Name ) FillFromRDNSequence (rdns *RDNSequence ) {
for _ , rdn := range *rdns {
if len (rdn ) == 0 {
continue
}
for _ , atv := range rdn {
n .Names = append (n .Names , atv )
value , ok := atv .Value .(string )
if !ok {
continue
}
t := atv .Type
if len (t ) == 4 && t [0 ] == 2 && t [1 ] == 5 && t [2 ] == 4 {
switch t [3 ] {
case 3 :
n .CommonName = value
case 5 :
n .SerialNumber = value
case 6 :
n .Country = append (n .Country , value )
case 7 :
n .Locality = append (n .Locality , value )
case 8 :
n .Province = append (n .Province , value )
case 9 :
n .StreetAddress = append (n .StreetAddress , value )
case 10 :
n .Organization = append (n .Organization , value )
case 11 :
n .OrganizationalUnit = append (n .OrganizationalUnit , value )
case 17 :
n .PostalCode = append (n .PostalCode , value )
}
}
}
}
}
var (
oidCountry = []int {2 , 5 , 4 , 6 }
oidOrganization = []int {2 , 5 , 4 , 10 }
oidOrganizationalUnit = []int {2 , 5 , 4 , 11 }
oidCommonName = []int {2 , 5 , 4 , 3 }
oidSerialNumber = []int {2 , 5 , 4 , 5 }
oidLocality = []int {2 , 5 , 4 , 7 }
oidProvince = []int {2 , 5 , 4 , 8 }
oidStreetAddress = []int {2 , 5 , 4 , 9 }
oidPostalCode = []int {2 , 5 , 4 , 17 }
)
func (n Name ) appendRDNs (in RDNSequence , values []string , oid asn1 .ObjectIdentifier ) RDNSequence {
if len (values ) == 0 || oidInAttributeTypeAndValue (oid , n .ExtraNames ) {
return in
}
s := make ([]AttributeTypeAndValue , len (values ))
for i , value := range values {
s [i ].Type = oid
s [i ].Value = value
}
return append (in , s )
}
func (n Name ) ToRDNSequence () (ret RDNSequence ) {
ret = n .appendRDNs (ret , n .Country , oidCountry )
ret = n .appendRDNs (ret , n .Province , oidProvince )
ret = n .appendRDNs (ret , n .Locality , oidLocality )
ret = n .appendRDNs (ret , n .StreetAddress , oidStreetAddress )
ret = n .appendRDNs (ret , n .PostalCode , oidPostalCode )
ret = n .appendRDNs (ret , n .Organization , oidOrganization )
ret = n .appendRDNs (ret , n .OrganizationalUnit , oidOrganizationalUnit )
if len (n .CommonName ) > 0 {
ret = n .appendRDNs (ret , []string {n .CommonName }, oidCommonName )
}
if len (n .SerialNumber ) > 0 {
ret = n .appendRDNs (ret , []string {n .SerialNumber }, oidSerialNumber )
}
for _ , atv := range n .ExtraNames {
ret = append (ret , []AttributeTypeAndValue {atv })
}
return ret
}
func (n Name ) String () string {
var rdns RDNSequence
if n .ExtraNames == nil {
for _ , atv := range n .Names {
t := atv .Type
if len (t ) == 4 && t [0 ] == 2 && t [1 ] == 5 && t [2 ] == 4 {
switch t [3 ] {
case 3 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 17 :
continue
}
}
rdns = append (rdns , []AttributeTypeAndValue {atv })
}
}
rdns = append (rdns , n .ToRDNSequence ()...)
return rdns .String ()
}
func oidInAttributeTypeAndValue (oid asn1 .ObjectIdentifier , atv []AttributeTypeAndValue ) bool {
for _ , a := range atv {
if a .Type .Equal (oid ) {
return true
}
}
return false
}
type CertificateList struct {
TBSCertList TBSCertificateList
SignatureAlgorithm AlgorithmIdentifier
SignatureValue asn1 .BitString
}
func (certList *CertificateList ) HasExpired (now time .Time ) bool {
return !now .Before (certList .TBSCertList .NextUpdate )
}
type TBSCertificateList struct {
Raw asn1 .RawContent
Version int `asn1:"optional,default:0"`
Signature AlgorithmIdentifier
Issuer RDNSequence
ThisUpdate time .Time
NextUpdate time .Time `asn1:"optional"`
RevokedCertificates []RevokedCertificate `asn1:"optional"`
Extensions []Extension `asn1:"tag:0,optional,explicit"`
}
type RevokedCertificate struct {
SerialNumber *big .Int
RevocationTime time .Time
Extensions []Extension `asn1:"optional"`
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .