Skip to content

Commit 38b8240

Browse files
author
Andy Martin
committed
Added support for general OID names in CSRs
1 parent 23b638f commit 38b8240

File tree

2 files changed

+65
-10
lines changed

2 files changed

+65
-10
lines changed

csr/csr.go

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ import (
1212
"encoding/asn1"
1313
"encoding/pem"
1414
"errors"
15+
"fmt"
1516
"net"
1617
"net/mail"
1718
"net/url"
19+
"strconv"
1820
"strings"
1921

2022
cferr "github.com/cloudflare/cfssl/errors"
@@ -30,12 +32,13 @@ const (
3032

3133
// A Name contains the SubjectInfo fields.
3234
type Name struct {
33-
C string `json:"C,omitempty" yaml:"C,omitempty"` // Country
34-
ST string `json:"ST,omitempty" yaml:"ST,omitempty"` // State
35-
L string `json:"L,omitempty" yaml:"L,omitempty"` // Locality
36-
O string `json:"O,omitempty" yaml:"O,omitempty"` // OrganisationName
37-
OU string `json:"OU,omitempty" yaml:"OU,omitempty"` // OrganisationalUnitName
38-
SerialNumber string `json:"SerialNumber,omitempty" yaml:"SerialNumber,omitempty"`
35+
C string `json:"C,omitempty" yaml:"C,omitempty"` // Country
36+
ST string `json:"ST,omitempty" yaml:"ST,omitempty"` // State
37+
L string `json:"L,omitempty" yaml:"L,omitempty"` // Locality
38+
O string `json:"O,omitempty" yaml:"O,omitempty"` // OrganisationName
39+
OU string `json:"OU,omitempty" yaml:"OU,omitempty"` // OrganisationalUnitName
40+
SerialNumber string `json:"SerialNumber,omitempty" yaml:"SerialNumber,omitempty"`
41+
OID map[string]string `json:"OID,omitempty", yaml:"OID,omitempty"`
3942
}
4043

4144
// A KeyRequest contains the algorithm and key size for a new private key.
@@ -157,8 +160,24 @@ func appendIf(s string, a *[]string) {
157160
}
158161
}
159162

163+
func OIDFromString(s string) (asn1.ObjectIdentifier, error) {
164+
var oid []int
165+
parts := strings.Split(s, ".")
166+
if len(parts) < 1 {
167+
return oid, fmt.Errorf("invalid OID string: %s", s)
168+
}
169+
for _, p := range parts {
170+
i, err := strconv.Atoi(p)
171+
if err != nil {
172+
return nil, fmt.Errorf("invalid OID part %s", p)
173+
}
174+
oid = append(oid, i)
175+
}
176+
return oid, nil
177+
}
178+
160179
// Name returns the PKIX name for the request.
161-
func (cr *CertificateRequest) Name() pkix.Name {
180+
func (cr *CertificateRequest) Name() (pkix.Name, error) {
162181
var name pkix.Name
163182
name.CommonName = cr.CN
164183

@@ -168,9 +187,16 @@ func (cr *CertificateRequest) Name() pkix.Name {
168187
appendIf(n.L, &name.Locality)
169188
appendIf(n.O, &name.Organization)
170189
appendIf(n.OU, &name.OrganizationalUnit)
190+
for k, v := range n.OID {
191+
oid, err := OIDFromString(k)
192+
if err != nil {
193+
return name, err
194+
}
195+
name.ExtraNames = append(name.ExtraNames, pkix.AttributeTypeAndValue{Type: oid, Value: v})
196+
}
171197
}
172198
name.SerialNumber = cr.SerialNumber
173-
return name
199+
return name, nil
174200
}
175201

176202
// BasicConstraints CSR information RFC 5280, 4.2.1.9
@@ -234,6 +260,7 @@ func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) {
234260
// from an existing certificate. For a root certificate, the CA expiry
235261
// length is calculated as the duration between cert.NotAfter and cert.NotBefore.
236262
func ExtractCertificateRequest(cert *x509.Certificate) *CertificateRequest {
263+
fmt.Printf("ExctractCertificateRequest %+v\n", *cert)
237264
req := New()
238265
req.CN = cert.Subject.CommonName
239266
req.Names = getNames(cert.Subject)
@@ -367,8 +394,13 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro
367394
return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
368395
}
369396

397+
subj, err := req.Name()
398+
if err != nil {
399+
return nil, err
400+
}
401+
370402
var tpl = x509.CertificateRequest{
371-
Subject: req.Name(),
403+
Subject: subj,
372404
SignatureAlgorithm: sigAlgo,
373405
}
374406

signer/signer.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ func DefaultSigAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
172172
}
173173
}
174174

175+
func isCommonAttr(t []int) bool {
176+
return (len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 && (t[3] == 3 || (t[3] >= 5 && t[3] <= 11) || t[3] == 17))
177+
}
178+
175179
// ParseCertificateRequest takes an incoming certificate request and
176180
// builds a certificate template from it.
177181
func ParseCertificateRequest(s Signer, p *config.SigningProfile, csrBytes []byte) (template *x509.Certificate, err error) {
@@ -181,14 +185,33 @@ func ParseCertificateRequest(s Signer, p *config.SigningProfile, csrBytes []byte
181185
return
182186
}
183187

188+
var r pkix.RDNSequence
189+
_, err = asn1.Unmarshal(csrv.RawSubject, &r)
190+
191+
if err != nil {
192+
err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
193+
return
194+
}
195+
196+
var subject pkix.Name
197+
subject.FillFromRDNSequence(&r)
198+
199+
for _, v := range r {
200+
for _, vv := range v {
201+
if !isCommonAttr(vv.Type) {
202+
subject.ExtraNames = append(subject.ExtraNames, vv)
203+
}
204+
}
205+
}
206+
184207
err = csrv.CheckSignature()
185208
if err != nil {
186209
err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err)
187210
return
188211
}
189212

190213
template = &x509.Certificate{
191-
Subject: csrv.Subject,
214+
Subject: subject,
192215
PublicKeyAlgorithm: csrv.PublicKeyAlgorithm,
193216
PublicKey: csrv.PublicKey,
194217
SignatureAlgorithm: s.SigAlgo(),

0 commit comments

Comments
 (0)