Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
G
golang
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
golang
Commits
32c3c953
Commit
32c3c953
authored
Feb 19, 2010
by
Adam Langley
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
crypto/x509: support certificate creation.
R=rsc CC=golang-dev
https://golang.org/cl/212041
parent
55828cee
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
280 additions
and
2 deletions
+280
-2
x509.go
src/pkg/crypto/x509/x509.go
+230
-2
x509_test.go
src/pkg/crypto/x509/x509_test.go
+50
-0
No files found.
src/pkg/crypto/x509/x509.go
View file @
32c3c953
...
...
@@ -12,6 +12,7 @@ import (
"crypto/rsa"
"crypto/sha1"
"hash"
"io"
"os"
"strings"
"time"
...
...
@@ -69,6 +70,21 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
return
}
// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
func
MarshalPKCS1PrivateKey
(
key
*
rsa
.
PrivateKey
)
[]
byte
{
priv
:=
pkcs1PrivateKey
{
Version
:
1
,
N
:
asn1
.
RawValue
{
Tag
:
2
,
Bytes
:
key
.
PublicKey
.
N
.
Bytes
()},
E
:
key
.
PublicKey
.
E
,
D
:
asn1
.
RawValue
{
Tag
:
2
,
Bytes
:
key
.
D
.
Bytes
()},
P
:
asn1
.
RawValue
{
Tag
:
2
,
Bytes
:
key
.
P
.
Bytes
()},
Q
:
asn1
.
RawValue
{
Tag
:
2
,
Bytes
:
key
.
Q
.
Bytes
()},
}
b
,
_
:=
asn1
.
MarshalToMemory
(
priv
)
return
b
}
// These structures reflect the ASN.1 structure of X.509 certificates.:
type
certificate
struct
{
...
...
@@ -86,8 +102,8 @@ type tbsCertificate struct {
Validity
validity
Subject
rdnSequence
PublicKey
publicKeyInfo
UniqueId
asn1
.
BitString
"optional,
explicit,
tag:1"
SubjectUniqueId
asn1
.
BitString
"optional,
explicit,
tag:2"
UniqueId
asn1
.
BitString
"optional,tag:1"
SubjectUniqueId
asn1
.
BitString
"optional,tag:2"
Extensions
[]
extension
"optional,explicit,tag:3"
}
...
...
@@ -188,6 +204,64 @@ func (n *Name) fillFromRDNSequence(rdns *rdnSequence) {
}
}
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
}
oidLocatity
=
[]
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
)
toRDNSequence
()
(
ret
rdnSequence
)
{
ret
=
make
([]
relativeDistinguishedNameSET
,
9
/* maximum number of elements */
)
i
:=
0
if
len
(
n
.
Country
)
>
0
{
ret
[
i
]
=
[]
attributeTypeAndValue
{
attributeTypeAndValue
{
oidCountry
,
n
.
Country
}}
i
++
}
if
len
(
n
.
Organization
)
>
0
{
ret
[
i
]
=
[]
attributeTypeAndValue
{
attributeTypeAndValue
{
oidOrganization
,
n
.
Organization
}}
i
++
}
if
len
(
n
.
OrganizationalUnit
)
>
0
{
ret
[
i
]
=
[]
attributeTypeAndValue
{
attributeTypeAndValue
{
oidOrganizationalUnit
,
n
.
OrganizationalUnit
}}
i
++
}
if
len
(
n
.
CommonName
)
>
0
{
ret
[
i
]
=
[]
attributeTypeAndValue
{
attributeTypeAndValue
{
oidCommonName
,
n
.
CommonName
}}
i
++
}
if
len
(
n
.
SerialNumber
)
>
0
{
ret
[
i
]
=
[]
attributeTypeAndValue
{
attributeTypeAndValue
{
oidSerialNumber
,
n
.
SerialNumber
}}
i
++
}
if
len
(
n
.
Locality
)
>
0
{
ret
[
i
]
=
[]
attributeTypeAndValue
{
attributeTypeAndValue
{
oidLocatity
,
n
.
Locality
}}
i
++
}
if
len
(
n
.
Province
)
>
0
{
ret
[
i
]
=
[]
attributeTypeAndValue
{
attributeTypeAndValue
{
oidProvince
,
n
.
Province
}}
i
++
}
if
len
(
n
.
StreetAddress
)
>
0
{
ret
[
i
]
=
[]
attributeTypeAndValue
{
attributeTypeAndValue
{
oidStreetAddress
,
n
.
StreetAddress
}}
i
++
}
if
len
(
n
.
PostalCode
)
>
0
{
ret
[
i
]
=
[]
attributeTypeAndValue
{
attributeTypeAndValue
{
oidPostalCode
,
n
.
PostalCode
}}
i
++
}
// Adding another RDN here? Remember to update the maximum number of
// elements in the make() at the top of the function.
return
ret
[
0
:
i
]
}
func
getSignatureAlgorithmFromOID
(
oid
[]
int
)
SignatureAlgorithm
{
if
len
(
oid
)
==
7
&&
oid
[
0
]
==
1
&&
oid
[
1
]
==
2
&&
oid
[
2
]
==
840
&&
oid
[
3
]
==
113549
&&
oid
[
4
]
==
1
&&
oid
[
5
]
==
1
{
...
...
@@ -589,3 +663,157 @@ func ParseCertificates(asn1Data []byte) ([]*Certificate, os.Error) {
return
ret
,
nil
}
func
reverseBitsInAByte
(
in
byte
)
byte
{
b1
:=
in
>>
4
|
in
<<
4
b2
:=
b1
>>
2
&
0x33
|
b1
<<
2
&
0xcc
b3
:=
b2
>>
1
&
0x55
|
b2
<<
1
&
0xaa
return
b3
}
var
(
oidExtensionSubjectKeyId
=
[]
int
{
2
,
5
,
29
,
14
}
oidExtensionKeyUsage
=
[]
int
{
2
,
5
,
29
,
15
}
oidExtensionAuthorityKeyId
=
[]
int
{
2
,
5
,
29
,
35
}
oidExtensionBasicConstraints
=
[]
int
{
2
,
5
,
29
,
19
}
oidExtensionSubjectAltName
=
[]
int
{
2
,
5
,
29
,
17
}
)
func
buildExtensions
(
template
*
Certificate
)
(
ret
[]
extension
,
err
os
.
Error
)
{
ret
=
make
([]
extension
,
5
/* maximum number of elements. */
)
n
:=
0
if
template
.
KeyUsage
!=
0
{
ret
[
n
]
.
Id
=
oidExtensionKeyUsage
ret
[
n
]
.
Critical
=
true
var
a
[
2
]
byte
a
[
0
]
=
reverseBitsInAByte
(
byte
(
template
.
KeyUsage
))
a
[
1
]
=
reverseBitsInAByte
(
byte
(
template
.
KeyUsage
>>
8
))
l
:=
1
if
a
[
1
]
!=
0
{
l
=
2
}
ret
[
n
]
.
Value
,
err
=
asn1
.
MarshalToMemory
(
asn1
.
BitString
{
Bytes
:
a
[
0
:
l
],
BitLength
:
l
*
8
})
if
err
!=
nil
{
return
}
n
++
}
if
template
.
BasicConstraintsValid
{
ret
[
n
]
.
Id
=
oidExtensionBasicConstraints
ret
[
n
]
.
Value
,
err
=
asn1
.
MarshalToMemory
(
basicConstraints
{
template
.
IsCA
,
template
.
MaxPathLen
})
ret
[
n
]
.
Critical
=
true
if
err
!=
nil
{
return
}
n
++
}
if
len
(
template
.
SubjectKeyId
)
>
0
{
ret
[
n
]
.
Id
=
oidExtensionSubjectKeyId
ret
[
n
]
.
Value
,
err
=
asn1
.
MarshalToMemory
(
template
.
SubjectKeyId
)
if
err
!=
nil
{
return
}
n
++
}
if
len
(
template
.
AuthorityKeyId
)
>
0
{
ret
[
n
]
.
Id
=
oidExtensionAuthorityKeyId
ret
[
n
]
.
Value
,
err
=
asn1
.
MarshalToMemory
(
authKeyId
{
template
.
AuthorityKeyId
})
if
err
!=
nil
{
return
}
n
++
}
if
len
(
template
.
DNSNames
)
>
0
{
ret
[
n
]
.
Id
=
oidExtensionSubjectAltName
rawValues
:=
make
([]
asn1
.
RawValue
,
len
(
template
.
DNSNames
))
for
i
,
name
:=
range
template
.
DNSNames
{
rawValues
[
i
]
=
asn1
.
RawValue
{
Tag
:
2
,
Class
:
2
,
Bytes
:
strings
.
Bytes
(
name
)}
}
ret
[
n
]
.
Value
,
err
=
asn1
.
MarshalToMemory
(
rawValues
)
if
err
!=
nil
{
return
}
n
++
}
// Adding another extension here? Remember to update the maximum number
// of elements in the make() at the top of the function.
return
ret
[
0
:
n
],
nil
}
var
(
oidSHA1WithRSA
=
[]
int
{
1
,
2
,
840
,
113549
,
1
,
1
,
5
}
oidRSA
=
[]
int
{
1
,
2
,
840
,
113549
,
1
,
1
,
1
}
)
// CreateSelfSignedCertificate creates a new certificate based on
// a template. The following members of template are used: SerialNumber,
// Subject, NotBefore, NotAfter, KeyUsage, BasicConstraintsValid, IsCA,
// MaxPathLen, SubjectKeyId, DNSNames.
//
// The certificate is signed by parent. If parent is equal to template then the
// certificate is self-signed.
//
// The returned slice is the certificate in DER encoding.
func
CreateCertificate
(
rand
io
.
Reader
,
template
,
parent
*
Certificate
,
priv
*
rsa
.
PrivateKey
)
(
cert
[]
byte
,
err
os
.
Error
)
{
asn1PublicKey
,
err
:=
asn1
.
MarshalToMemory
(
rsaPublicKey
{
N
:
asn1
.
RawValue
{
Tag
:
2
,
Bytes
:
priv
.
PublicKey
.
N
.
Bytes
()},
E
:
priv
.
PublicKey
.
E
,
})
if
err
!=
nil
{
return
}
if
len
(
template
.
SubjectKeyId
)
>
0
&&
len
(
parent
.
SubjectKeyId
)
>
0
{
template
.
AuthorityKeyId
=
parent
.
SubjectKeyId
}
extensions
,
err
:=
buildExtensions
(
template
)
if
err
!=
nil
{
return
}
encodedPublicKey
:=
asn1
.
BitString
{
BitLength
:
len
(
asn1PublicKey
)
*
8
,
Bytes
:
asn1PublicKey
}
c
:=
tbsCertificate
{
Version
:
3
,
SerialNumber
:
asn1
.
RawValue
{
Bytes
:
template
.
SerialNumber
,
Tag
:
2
},
SignatureAlgorithm
:
algorithmIdentifier
{
oidSHA1WithRSA
},
Issuer
:
parent
.
Subject
.
toRDNSequence
(),
Validity
:
validity
{
template
.
NotBefore
,
template
.
NotAfter
},
Subject
:
template
.
Subject
.
toRDNSequence
(),
PublicKey
:
publicKeyInfo
{
algorithmIdentifier
{
oidRSA
},
encodedPublicKey
},
Extensions
:
extensions
,
}
tbsCertContents
,
err
:=
asn1
.
MarshalToMemory
(
c
)
if
err
!=
nil
{
return
}
c
.
Raw
=
tbsCertContents
h
:=
sha1
.
New
()
h
.
Write
(
tbsCertContents
)
digest
:=
h
.
Sum
()
signature
,
err
:=
rsa
.
SignPKCS1v15
(
rand
,
priv
,
rsa
.
HashSHA1
,
digest
)
if
err
!=
nil
{
return
}
cert
,
err
=
asn1
.
MarshalToMemory
(
certificate
{
c
,
algorithmIdentifier
{
oidSHA1WithRSA
},
asn1
.
BitString
{
Bytes
:
signature
,
BitLength
:
len
(
signature
)
*
8
},
})
return
}
src/pkg/crypto/x509/x509_test.go
View file @
32c3c953
...
...
@@ -9,9 +9,11 @@ import (
"crypto/rsa"
"encoding/hex"
"encoding/pem"
"os"
"reflect"
"strings"
"testing"
"time"
)
func
TestParsePKCS1PrivateKey
(
t
*
testing
.
T
)
{
...
...
@@ -142,3 +144,51 @@ var certBytes = "308203223082028ba00302010202106edf0d9499fd4533dd1297fc42a93be13
"e9e83994dcab72792f06bfab8170c4a8edea5334edef1e53d906c7562bd15cf4d18a8eb42bb137"
+
"9048084225c53e8acb7feb6f04d16dc574a2f7a27c7b603c77cd0ece48027f012fb69b37e02a2a"
+
"36dcd585d6ace53f546f961e05af"
func
TestCreateSelfSignedCertificate
(
t
*
testing
.
T
)
{
urandom
,
err
:=
os
.
Open
(
"/dev/urandom"
,
os
.
O_RDONLY
,
0
)
if
err
!=
nil
{
t
.
Errorf
(
"failed to open /dev/urandom"
)
}
block
,
_
:=
pem
.
Decode
(
strings
.
Bytes
(
pemPrivateKey
))
priv
,
err
:=
ParsePKCS1PrivateKey
(
block
.
Bytes
)
if
err
!=
nil
{
t
.
Errorf
(
"Failed to parse private key: %s"
,
err
)
return
}
template
:=
Certificate
{
SerialNumber
:
[]
byte
{
1
},
Subject
:
Name
{
CommonName
:
"test.example.com"
,
Organization
:
"Acme Co"
,
},
NotBefore
:
time
.
SecondsToUTC
(
1000
),
NotAfter
:
time
.
SecondsToUTC
(
100000
),
SubjectKeyId
:
[]
byte
{
1
,
2
,
3
,
4
},
KeyUsage
:
KeyUsageCertSign
,
BasicConstraintsValid
:
true
,
IsCA
:
true
,
DNSNames
:
[]
string
{
"test.example.com"
},
}
derBytes
,
err
:=
CreateCertificate
(
urandom
,
&
template
,
&
template
,
priv
)
if
err
!=
nil
{
t
.
Errorf
(
"Failed to create certificate: %s"
,
err
)
return
}
cert
,
err
:=
ParseCertificate
(
derBytes
)
if
err
!=
nil
{
t
.
Errorf
(
"Failed to parse certificate: %s"
,
err
)
return
}
err
=
cert
.
CheckSignatureFrom
(
cert
)
if
err
!=
nil
{
t
.
Errorf
(
"Signature verification failed: %s"
,
err
)
return
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment