-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 5c8886f
Showing
4 changed files
with
274 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module test-crts | ||
|
||
go 1.18 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"crypto/ecdsa" | ||
"crypto/elliptic" | ||
"crypto/rand" | ||
"crypto/sha256" | ||
"crypto/x509" | ||
"crypto/x509/pkix" | ||
"encoding/pem" | ||
"log" | ||
"math/big" | ||
"time" | ||
) | ||
|
||
func parseX509Certificate(contents []byte) (*x509.Certificate, error) { | ||
block, _ := pem.Decode(contents) | ||
crt, err := x509.ParseCertificate(block.Bytes) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return crt, nil | ||
} | ||
|
||
// compute Subject Key Identifier using RFC 7093, Section 2, Method 4 | ||
func computeSKI(privKey *ecdsa.PrivateKey) []byte { | ||
// Marshall the public key | ||
raw := elliptic.Marshal(privKey.Curve, privKey.PublicKey.X, privKey.PublicKey.Y) | ||
|
||
// Hash it | ||
hash := sha256.Sum256(raw) | ||
return hash[:] | ||
} | ||
func CreateDefaultCA() (*x509.Certificate, *ecdsa.PrivateKey, error) { | ||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) | ||
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) | ||
if err != nil { | ||
log.Fatalf("Failed to generate serial number: %v", err) | ||
return nil, nil, err | ||
} | ||
log.Printf("serialNumber: %v", serialNumber) | ||
caPrivKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
expiry := 3650 * 24 * time.Hour | ||
notBefore := time.Now().Round(time.Minute).Add(-5 * time.Minute).UTC() | ||
template := x509.Certificate{ | ||
SerialNumber: serialNumber, | ||
//Subject: pkix.Name{ | ||
// Organization: []string{"Kyma"}, | ||
// Country: []string{"DE"}, | ||
// Locality: []string{"Berlin"}, | ||
// OrganizationalUnit: []string{"Kyma"}, | ||
// StreetAddress: []string{"Karl-Liebknecht-Str. 3"}, | ||
// CommonName: "Kyma", | ||
//}, | ||
NotBefore: notBefore, | ||
NotAfter: notBefore.Add(expiry).UTC(), | ||
//IsCA: true, | ||
//SubjectKeyId: computeSKI(caPrivKey), | ||
//ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, | ||
//KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageCRLSign | x509.KeyUsageKeyEncipherment, | ||
BasicConstraintsValid: true, | ||
} | ||
subject := pkix.Name{ | ||
Organization: []string{"Kyma"}, | ||
//Country: []string{"US"}, | ||
//Locality: []string{"Berlin"}, | ||
//OrganizationalUnit: []string{"Kyma"}, | ||
//StreetAddress: []string{"Karl-Liebknecht-Str. 3"}, | ||
CommonName: "kyma", | ||
} | ||
template.IsCA = true | ||
template.KeyUsage |= x509.KeyUsageDigitalSignature | | ||
x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign | | ||
x509.KeyUsageCRLSign | ||
template.ExtKeyUsage = []x509.ExtKeyUsage{ | ||
x509.ExtKeyUsageClientAuth, | ||
x509.ExtKeyUsageServerAuth, | ||
} | ||
template.Subject = subject | ||
template.SubjectKeyId = computeSKI(caPrivKey) | ||
caBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &caPrivKey.PublicKey, caPrivKey) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
crt, err := x509.ParseCertificate(caBytes) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
return crt, caPrivKey, nil | ||
} | ||
func EncodeX509Certificate(crt *x509.Certificate) []byte { | ||
pemPk := pem.EncodeToMemory(&pem.Block{ | ||
Type: "CERTIFICATE", | ||
Bytes: crt.Raw, | ||
}) | ||
return pemPk | ||
|
||
} | ||
func main() { | ||
caCert, _, err := CreateDefaultCA() | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
_ = caCert | ||
certToCheck := EncodeX509Certificate(caCert) | ||
// certToCheck := []byte(`-----BEGIN CERTIFICATE----- | ||
//MIICQTCCAeagAwIBAgIRAIlyPiTZkAYHopLI/MMzu5gwCgYIKoZIzj0EAwIwajEL | ||
//MAkGA1UEBhMCRVMxETAPBgNVBAcTCEFsaWNhbnRlMREwDwYDVQQJEwhBbGljYW50 | ||
//ZTEZMBcGA1UEChMQS3VuZyBGdSBTb2Z0d2FyZTENMAsGA1UECxMEVGVjaDELMAkG | ||
//A1UEAxMCY2EwHhcNMjMwMTAzMTA1NTIyWhcNMzMwMTA0MTA1NTIyWjBqMQswCQYD | ||
//VQQGEwJFUzERMA8GA1UEBxMIQWxpY2FudGUxETAPBgNVBAkTCEFsaWNhbnRlMRkw | ||
//FwYDVQQKExBLdW5nIEZ1IFNvZnR3YXJlMQ0wCwYDVQQLEwRUZWNoMQswCQYDVQQD | ||
//EwJjYTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABB9O3T8iBC2OpFHe6BWJNEh4 | ||
//mxSR8AmyqKZKyjCLy9HnjDeYVoVQLK7Qouvc0iyTs+WTscv+iTkjzEkm9pfWdEqj | ||
//bTBrMA4GA1UdDwEB/wQEAwIBpjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH | ||
//AwEwDwYDVR0TAQH/BAUwAwEB/zApBgNVHQ4EIgQgV0rtlf59BQ7pjZHD+RF0zIIj | ||
//mmgjUWR+6Q+npPY9mIcwCgYIKoZIzj0EAwIDSQAwRgIhAJqVsD9z4GSB26uKQNqW | ||
//swGxS0xvdrwzJ8Wm/CKNPnBLAiEAkRuMG+YojjB/UKkArQEQNcxy8CzAUPoCbmG7 | ||
//cN2el6c= | ||
//-----END CERTIFICATE-----`) | ||
log.Printf("certToCheck: %s", certToCheck) | ||
certPool := x509.NewCertPool() | ||
parentCert, err := parseX509Certificate([]byte(certToCheck)) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
_ = certPool.AppendCertsFromPEM([]byte(certToCheck)) | ||
x509Cert, err := parseX509Certificate([]byte(certToCheck)) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
log.Printf("parentCert: %v", parentCert) | ||
s := new(big.Int) | ||
s = s.Set(GetCurveHalfOrdersAt(elliptic.P256())) | ||
s = s.Add(s, big.NewInt(1)) | ||
|
||
lowS, err := IsLowS(parentCert.PublicKey.(*ecdsa.PublicKey), s) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
log.Printf("lowS: %v", lowS) | ||
expectedSig, err := SignatureToLowS(parentCert.PublicKey.(*ecdsa.PublicKey), x509Cert.Signature) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
log.Printf("expectedSig: %v currentSig: %v", expectedSig, x509Cert.Signature) | ||
|
||
equalSig := bytes.Equal(x509Cert.Signature, expectedSig) | ||
log.Printf("equalSig: %v", equalSig) | ||
|
||
options := x509.VerifyOptions{} | ||
options.Roots = certPool | ||
_, err = x509Cert.Verify(options) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
log.Printf("Hello, world.") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/* | ||
Copyright IBM Corp. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package main | ||
|
||
import ( | ||
"crypto/ecdsa" | ||
"crypto/elliptic" | ||
"encoding/asn1" | ||
"errors" | ||
"fmt" | ||
"log" | ||
"math/big" | ||
) | ||
|
||
type ECDSASignature struct { | ||
R, S *big.Int | ||
} | ||
|
||
// curveHalfOrders contains the precomputed curve group orders halved. | ||
// It is used to ensure that signature' S value is lower or equal to the | ||
// curve group order halved. We accept only low-S signatures. | ||
// They are precomputed for efficiency reasons. | ||
var curveHalfOrders = map[elliptic.Curve]*big.Int{ | ||
elliptic.P224(): new(big.Int).Rsh(elliptic.P224().Params().N, 1), | ||
elliptic.P256(): new(big.Int).Rsh(elliptic.P256().Params().N, 1), | ||
elliptic.P384(): new(big.Int).Rsh(elliptic.P384().Params().N, 1), | ||
elliptic.P521(): new(big.Int).Rsh(elliptic.P521().Params().N, 1), | ||
} | ||
|
||
func GetCurveHalfOrdersAt(c elliptic.Curve) *big.Int { | ||
return big.NewInt(0).Set(curveHalfOrders[c]) | ||
} | ||
|
||
func MarshalECDSASignature(r, s *big.Int) ([]byte, error) { | ||
return asn1.Marshal(ECDSASignature{r, s}) | ||
} | ||
|
||
func UnmarshalECDSASignature(raw []byte) (*big.Int, *big.Int, error) { | ||
// Unmarshal | ||
sig := new(ECDSASignature) | ||
_, err := asn1.Unmarshal(raw, sig) | ||
if err != nil { | ||
return nil, nil, fmt.Errorf("failed unmashalling signature [%s]", err) | ||
} | ||
|
||
// Validate sig | ||
if sig.R == nil { | ||
return nil, nil, errors.New("invalid signature, R must be different from nil") | ||
} | ||
if sig.S == nil { | ||
return nil, nil, errors.New("invalid signature, S must be different from nil") | ||
} | ||
|
||
if sig.R.Sign() != 1 { | ||
return nil, nil, errors.New("invalid signature, R must be larger than zero") | ||
} | ||
if sig.S.Sign() != 1 { | ||
return nil, nil, errors.New("invalid signature, S must be larger than zero") | ||
} | ||
|
||
return sig.R, sig.S, nil | ||
} | ||
|
||
func SignatureToLowS(k *ecdsa.PublicKey, signature []byte) ([]byte, error) { | ||
r, s, err := UnmarshalECDSASignature(signature) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
s, err = ToLowS(k, s) | ||
if err != nil { | ||
return nil, err | ||
} | ||
log.Printf("SignatureToLowS: s [%s]", s) | ||
return MarshalECDSASignature(r, s) | ||
} | ||
|
||
// IsLow checks that s is a low-S | ||
func IsLowS(k *ecdsa.PublicKey, s *big.Int) (bool, error) { | ||
halfOrder, ok := curveHalfOrders[k.Curve] | ||
if !ok { | ||
return false, fmt.Errorf("curve not recognized [%s]", k.Curve) | ||
} | ||
|
||
return s.Cmp(halfOrder) != 1, nil | ||
} | ||
|
||
func ToLowS(k *ecdsa.PublicKey, s *big.Int) (*big.Int, error) { | ||
lowS, err := IsLowS(k, s) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if !lowS { | ||
// Set s to N - s that will be then in the lower part of signature space | ||
// less or equal to half order | ||
s.Sub(k.Params().N, s) | ||
|
||
return s, nil | ||
} | ||
|
||
return s, nil | ||
} |