[OOM-K8S-CERT-EXTERNAL-PROVIDER] Add logging of supported CSR properties 46/114346/9
authorJan Malkiewicz <jan.malkiewicz@nokia.com>
Wed, 28 Oct 2020 07:19:08 +0000 (08:19 +0100)
committerJan Malkiewicz <jan.malkiewicz@nokia.com>
Thu, 29 Oct 2020 10:14:03 +0000 (11:14 +0100)
Issue-ID: OOM-2559
Signed-off-by: Jan Malkiewicz <jan.malkiewicz@nokia.com>
Change-Id: I8e6a55eea3d87b6bb5f3a26ca9a11d618bb61a77

certServiceK8sExternalProvider/src/cmpv2controller/certificate_request_controller.go
certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger.go
certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger_test.go
certServiceK8sExternalProvider/src/cmpv2provisioner/cmpv2_provisioner.go
certServiceK8sExternalProvider/src/x509/testdata/test_data.go [new file with mode: 0644]
certServiceK8sExternalProvider/src/x509/x509_utils.go [new file with mode: 0644]
certServiceK8sExternalProvider/src/x509/x509_utils_test.go [new file with mode: 0644]

index f77642c..03eef35 100644 (file)
@@ -43,6 +43,7 @@ import (
        "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api"
        "onap.org/oom-certservice/k8s-external-provider/src/cmpv2controller/logger"
        provisioners "onap.org/oom-certservice/k8s-external-provider/src/cmpv2provisioner"
+       x509utils "onap.org/oom-certservice/k8s-external-provider/src/x509"
 )
 
 const (
@@ -124,17 +125,25 @@ func (controller *CertificateRequestController) Reconcile(k8sRequest ctrl.Reques
        }
        privateKeyBytes := privateKeySecret.Data[privateKeySecretKey]
 
-       // 8. Log Certificate Request properties not supported or overridden by CertService API
-       logger.LogCertRequestProperties(ctrl.Log.WithName("CSR details"), certificateRequest)
+       // 8. Decode CSR
+       log.Info("Decoding CSR...")
+       csr, err := x509utils.DecodeCSR(certificateRequest.Spec.Request)
+       if err != nil {
+               controller.handleErrorFailedToDecodeCSR(ctx, log, err, certificateRequest)
+               return ctrl.Result{}, err
+       }
+
+       // 9. Log Certificate Request properties not supported or overridden by CertService API
+       logger.LogCertRequestProperties(ctrl.Log.WithName("CSR details"), certificateRequest, csr)
 
-       // 9. Sign CertificateRequest
+       // 10. Sign CertificateRequest
        signedPEM, trustedCAs, err := provisioner.Sign(ctx, certificateRequest, privateKeyBytes)
        if err != nil {
                controller.handleErrorFailedToSignCertificate(ctx, log, err, certificateRequest)
                return ctrl.Result{}, err
        }
 
-       // 10. Store signed certificates in CertificateRequest
+       // 11. Store signed certificates in CertificateRequest
        certificateRequest.Status.Certificate = signedPEM
        certificateRequest.Status.CA = trustedCAs
        if err := controller.updateCertificateRequestWithSignedCerficates(ctx, certificateRequest); err != nil {
@@ -221,6 +230,12 @@ func (controller *CertificateRequestController) handleErrorFailedToSignCertifica
        _ = controller.setStatus(ctx, certificateRequest, cmmeta.ConditionFalse, cmapi.CertificateRequestReasonFailed, "Failed to sign certificate request: %v", err)
 }
 
+func (controller *CertificateRequestController) handleErrorFailedToDecodeCSR(ctx context.Context, log logr.Logger, err error, certificateRequest *cmapi.CertificateRequest) {
+       log.Error(err, "Failed to decode certificate sign request")
+       _ = controller.setStatus(ctx, certificateRequest, cmmeta.ConditionFalse, cmapi.CertificateRequestReasonFailed, "Failed to decode CSR: %v", err)
+}
+
+
 func handleErrorResourceNotFound(log logr.Logger, err error) error {
        if apierrors.IsNotFound(err) {
                log.Error(err, "CertificateRequest resource not found")
index da439fb..0aaf48d 100644 (file)
@@ -21,8 +21,7 @@
 package logger
 
 import (
-       "crypto/x509"
-       "encoding/pem"
+       x509 "crypto/x509"
        "net"
        "net/url"
        "strconv"
@@ -36,9 +35,25 @@ const (
        CMPv2ServerName = "CMPv2 Server"
 )
 
-func LogCertRequestProperties(log logr.Logger, request *cmapi.CertificateRequest) {
+func LogCertRequestProperties(log logr.Logger, request *cmapi.CertificateRequest, csr *x509.CertificateRequest) {
+       logSupportedProperties(log, request, csr)
+       logPropertiesNotSupportedByCertService(log, request, csr)
        logPropertiesOverriddenByCMPv2Server(log, request)
-       logPropertiesNotSupportedByCertService(log, request)
+}
+
+func logSupportedProperties(log logr.Logger, request *cmapi.CertificateRequest, csr *x509.CertificateRequest) {
+       logSupportedProperty(log, csr.Subject.Organization, "organization")
+       logSupportedProperty(log, csr.Subject.OrganizationalUnit, "organization unit")
+       logSupportedProperty(log, csr.Subject.Country, "country")
+       logSupportedProperty(log, csr.Subject.Province, "state")
+       logSupportedProperty(log, csr.Subject.Locality, "location")
+       logSupportedProperty(log, csr.DNSNames, "dns names")
+}
+
+func logSupportedProperty(log logr.Logger, values []string, propertyName string) {
+       if len(values) > 0 {
+               log.Info(getSupportedMessage(propertyName, extractStringArray(values)))
+       }
 }
 
 func logPropertiesOverriddenByCMPv2Server(log logr.Logger, request *cmapi.CertificateRequest) {
@@ -58,53 +73,44 @@ func extractUsages(usages []cmapi.KeyUsage) string {
        return values
 }
 
-func getOverriddenMessage(property string, values string) string {
-       return "Property '" + property + "' with value: " + values + ", will be overridden by " + CMPv2ServerName
-}
-
-func logPropertiesNotSupportedByCertService(log logr.Logger, request *cmapi.CertificateRequest) {
+func logPropertiesNotSupportedByCertService(log logr.Logger, request *cmapi.CertificateRequest, csr *x509.CertificateRequest) {
 
-       block, _ := pem.Decode(request.Spec.Request)
-       cert, err := x509.ParseCertificateRequest(block.Bytes)
-       if err != nil {
-               log.Error(err, "Cannot parse Certificate Signing Request")
-       }
        //IP addresses in SANs
-       if len(cert.IPAddresses) > 0 {
-               log.Info(getNotSupportedMessage("ipAddresses", extractIPAddresses(cert.IPAddresses)))
+       if len(csr.IPAddresses) > 0 {
+               log.Info(getNotSupportedMessage("ipAddresses", extractIPAddresses(csr.IPAddresses)))
        }
        //URIs in SANs
-       if len(cert.URIs) > 0 {
-               log.Info(getNotSupportedMessage("uris", extractURIs(cert.URIs)))
+       if len(csr.URIs) > 0 {
+               log.Info(getNotSupportedMessage("uris", extractURIs(csr.URIs)))
        }
 
        //Email addresses in SANs
-       if len(cert.EmailAddresses) > 0 {
-               log.Info(getNotSupportedMessage("emailAddresses", extractStringArray(cert.EmailAddresses)))
+       if len(csr.EmailAddresses) > 0 {
+               log.Info(getNotSupportedMessage("emailAddresses", extractStringArray(csr.EmailAddresses)))
        }
 
        if request.Spec.IsCA == true {
                log.Info(getNotSupportedMessage("isCA", strconv.FormatBool(request.Spec.IsCA)))
        }
 
-       if len(cert.Subject.StreetAddress) > 0 {
-               log.Info(getNotSupportedMessage("subject.streetAddress", extractStringArray(cert.Subject.StreetAddress)))
+       if len(csr.Subject.StreetAddress) > 0 {
+               log.Info(getNotSupportedMessage("subject.streetAddress", extractStringArray(csr.Subject.StreetAddress)))
        }
 
-       if len(cert.Subject.PostalCode) > 0 {
-               log.Info(getNotSupportedMessage("subject.postalCodes", extractStringArray(cert.Subject.PostalCode)))
+       if len(csr.Subject.PostalCode) > 0 {
+               log.Info(getNotSupportedMessage("subject.postalCodes", extractStringArray(csr.Subject.PostalCode)))
        }
 
-       if len(cert.Subject.SerialNumber) > 0 {
-               log.Info(getNotSupportedMessage("subject.serialNumber", cert.Subject.SerialNumber))
+       if len(csr.Subject.SerialNumber) > 0 {
+               log.Info(getNotSupportedMessage("subject.serialNumber", csr.Subject.SerialNumber))
        }
 
 }
 
 func extractStringArray(strArray []string) string {
        values := ""
-       for _, emailSANs := range strArray {
-               values = values + emailSANs + ", "
+       for _, val := range strArray {
+               values = values + val + ", "
        }
        return values
 }
@@ -125,6 +131,14 @@ func extractIPAddresses(addresses []net.IP) string {
        return values
 }
 
-func getNotSupportedMessage(property string, values string) string {
-       return "WARNING: Property '" + property + "' with value: " + values + " is not supported by " + CertServiceName
+func getNotSupportedMessage(property string, value string) string {
+       return "WARNING: Property '" + property + "' with value: " + value + " is not supported by " + CertServiceName
+}
+
+func getSupportedMessage(property string, value string) string {
+       return "Property '" + property + "' with value: " + value + " will be sent in certificate signing request to " + CMPv2ServerName
+}
+
+func getOverriddenMessage(property string, values string) string {
+       return "Property '" + property + "' with value: " + values + " will be overridden by " + CMPv2ServerName
 }
index 7d1abc2..ea1076d 100644 (file)
@@ -33,12 +33,18 @@ import (
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/klog/v2"
        "k8s.io/klog/v2/klogr"
+
+       x509utils "onap.org/oom-certservice/k8s-external-provider/src/x509"
 )
 
 var checkedLogMessages = [7]string{"Property 'duration'", "Property 'usages'", "Property 'ipAddresses'",
        "Property 'isCA'", "Property 'subject.streetAddress'", "Property 'subject.postalCodes'",
        "Property 'subject.serialNumber'"}
 
+var supportedProperties = [7]string{"Property 'organization'", "Property 'organization unit'", "Property 'country'",
+       "Property 'state'", "Property 'location'", "Property 'dns names'"}
+
+
 func TestMain(m *testing.M) {
        klog.InitFlags(nil)
        flag.CommandLine.Set("v", "10")
@@ -55,8 +61,13 @@ func TestLogShouldNotProvideInformationAboutSkippedPropertiesIfNotExistInCSR(t *
        request := getCertificateRequestWithoutSkippedProperties()
        tmpWriteBuffer := getLogBuffer()
 
+       csr, err := x509utils.DecodeCSR(request.Spec.Request)
+       if err != nil {
+               assert.FailNow(t, "Could not parse Certificate Sign Request")
+       }
+
        //when
-       LogCertRequestProperties(logger, request)
+       LogCertRequestProperties(logger, request, csr)
        closeLogBuffer()
        logsArray := convertBufferToStringArray(tmpWriteBuffer)
        //then
@@ -71,8 +82,13 @@ func TestLogShouldProvideInformationAboutSkippedPropertiesIfExistInCSR(t *testin
        request := getCertificateRequestWithSkippedProperties()
        tmpWriteBuffer := getLogBuffer()
 
+       csr, err := x509utils.DecodeCSR(request.Spec.Request)
+       if err != nil {
+               assert.FailNow(t, "Could not parse Certificate Sign Request")
+       }
+
        //when
-       LogCertRequestProperties(logger, request)
+       LogCertRequestProperties(logger, request, csr)
        closeLogBuffer()
        logsArray := convertBufferToStringArray(tmpWriteBuffer)
 
@@ -82,6 +98,28 @@ func TestLogShouldProvideInformationAboutSkippedPropertiesIfExistInCSR(t *testin
        }
 }
 
+func TestLogShouldListSupportedProperties(t *testing.T) {
+       //given
+       logger := klogr.New()
+       request := getCertificateRequestWithoutSkippedProperties()
+       tmpWriteBuffer := getLogBuffer()
+
+       csr, err := x509utils.DecodeCSR(request.Spec.Request)
+       if err != nil {
+               assert.FailNow(t, "Could not parse Certificate Sign Request")
+       }
+
+       //when
+       LogCertRequestProperties(logger, request, csr)
+       closeLogBuffer()
+       logsArray := convertBufferToStringArray(tmpWriteBuffer)
+
+       //then
+       for _, logMsg := range supportedProperties {
+               assert.True(t, logsContainExpectedMessage(logsArray, logMsg), "Logs not contain: "+logMsg)
+       }
+}
+
 func getCertificateRequestWithoutSkippedProperties() *cmapi.CertificateRequest {
        request := new(cmapi.CertificateRequest)
        request.Spec.Request = []byte(csrWithoutSkippedProperties)
index c0304d7..6e09e68 100644 (file)
 package cmpv2provisioner
 
 import (
-       "bytes"
        "context"
        "crypto/x509"
-       "encoding/pem"
-       "fmt"
        "sync"
 
        certmanager "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
@@ -39,6 +36,7 @@ import (
 
        "onap.org/oom-certservice/k8s-external-provider/src/certserviceclient"
        "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api"
+       x509utils "onap.org/oom-certservice/k8s-external-provider/src/x509"
 )
 
 var collection = new(sync.Map)
@@ -96,7 +94,7 @@ func (ca *CertServiceCA) Sign(ctx context.Context, certificateRequest *certmanag
        csrBytes := certificateRequest.Spec.Request
        log.Info("Csr PEM: ", "bytes", csrBytes)
 
-       csr, err := decodeCSR(csrBytes)
+       csr, err := x509utils.DecodeCSR(csrBytes)
        if err != nil {
                return nil, nil, err
        }
@@ -113,7 +111,7 @@ func (ca *CertServiceCA) Sign(ctx context.Context, certificateRequest *certmanag
        // stored response as PEM
        cert := x509.Certificate{}
        cert.Raw = csr.Raw
-       encodedPEM, err := encodeX509(&cert)
+       encodedPEM, err := x509utils.EncodeX509(&cert)
        if err != nil {
                return nil, nil, err
        }
@@ -128,32 +126,3 @@ func (ca *CertServiceCA) Sign(ctx context.Context, certificateRequest *certmanag
 
        return signedPEM, trustedCA, nil
 }
-
-// decodeCSR decodes a certificate request in PEM format and returns the
-func decodeCSR(data []byte) (*x509.CertificateRequest, error) {
-       block, rest := pem.Decode(data)
-       if block == nil || len(rest) > 0 {
-               return nil, fmt.Errorf("unexpected CSR PEM on sign request")
-       }
-       if block.Type != "CERTIFICATE REQUEST" {
-               return nil, fmt.Errorf("PEM is not a certificate request")
-       }
-       csr, err := x509.ParseCertificateRequest(block.Bytes)
-       if err != nil {
-               return nil, fmt.Errorf("error parsing certificate request: %v", err)
-       }
-       if err := csr.CheckSignature(); err != nil {
-               return nil, fmt.Errorf("error checking certificate request signature: %v", err)
-       }
-       return csr, nil
-}
-
-// encodeX509 will encode a *x509.Certificate into PEM format.
-func encodeX509(cert *x509.Certificate) ([]byte, error) {
-       caPem := bytes.NewBuffer([]byte{})
-       err := pem.Encode(caPem, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
-       if err != nil {
-               return nil, err
-       }
-       return caPem.Bytes(), nil
-}
diff --git a/certServiceK8sExternalProvider/src/x509/testdata/test_data.go b/certServiceK8sExternalProvider/src/x509/testdata/test_data.go
new file mode 100644 (file)
index 0000000..dad5d09
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * ============LICENSE_START=======================================================
+ * oom-certservice-k8s-external-provider
+ * ================================================================================
+ * Copyright (C) 2020 Nokia. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package testdata
+
+
+const ValidCertificateSignRequest = (`-----BEGIN CERTIFICATE REQUEST-----
+MIIDgjCCAmoCAQAwgaQxCzAJBgNVBAYTAlBMMRMwEQYDVQQIEwpEb2xueVNsYXNr
+MRAwDgYDVQQHEwdXcm9jbGF3MREwDwYDVQQJEwhMb3RuaWN6YTEPMA0GA1UEERMG
+MTItMzQ1MQ0wCwYDVQQKEwRPTkFQMQ0wCwYDVQQLEwRvbmFwMRwwGgYDVQQDExNj
+ZXJ0aXNzdWVyLm9uYXAub3JnMQ4wDAYDVQQFEwUxMjM0NTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAPdrWRYpdGY6A9YEQ8mnQdOW7wzdaNHJ83ZrMPZd
+V7jBOMvQbTw6Oe/Q4vD+Dla7FmGqlAajNIgKRiUUQLKVmASELhCYhtW7Mn91qe6l
+xuyPyOEi9o8mArJosFAfPPF0nm9FQPi2qHgyi6C52QR7cKsgNPflpKVsEx9Y+Zns
+YBqkaX16BukvcHUANgsvZ3rLUVeiOsCi2ysVcsm+4XMvF6ejoqKJ9k7Ti0VrQtqh
+e1nKlaa4uP3dreeUXBMLfKUS7QrNavpiX6wVaohVp6p/AYQ2HZurMv86Q2E5D5SC
+ReEpVuWx+r4MI8dAHbYe09ntkRGIe8mVyxHHEWLNfZiwKGsCAwEAAaCBlzCBlAYJ
+KoZIhvcNAQkOMYGGMIGDMFUGA1UdEQROMEyCCWxvY2FsaG9zdIITY2VydGlzc3Vl
+ci5vbmFwLm9yZ4ENb25hcEBvbmFwLm9yZ4cEfwAAAYYVb25hcDovL2NsdXN0ZXIu
+bG9jYWwvMAsGA1UdDwQEAwICBDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
+AwIwDQYJKoZIhvcNAQELBQADggEBAHDMw3+fVOrbVnMI2g/IP40vt1eenkoriTHX
+dnjRRFio75nCNRJdLOJ9FU3wIgdDZwGaiXdn5NDQxCe0BWcbElDJSYR/xOi7V0AM
+2L3CrRAOhr2MjwX7CaOuYWcVtrbtIMf26NLKRXYPlGgc6YeofalDnezMJ/IuRQhj
+bcm17a8owa5dH9u/rmTmlrIT7PV4JHkZIogctIcSqod6xdr1mbi8G9DMFAqV+o7W
+9kV7XDKhTqYoBIsXwfehNMu3lo72VuklIyVNiEVz4mVzpeZy2DgjRjCLt106yDHZ
+f3nco6O4y2EyexBVKq6QRFfZDUab6YcoEVvPAio01RmFrHgnxHs=
+-----END CERTIFICATE REQUEST-----`)
+
+const InvalidCertificateSignRequest = (`-----BEGIN INVALID REQUEST-----
+MIIDgjCCAmoCAQAwgaQxCzAJBgNVBAYTAlBMMRMwEQYDVQQIEwpEb2xueVNsYXNr
+MRAwDgYDVQQHEwdXcm9jbGF3MREwDwYDVQQJEwhMb3RuaWN6YTEPMA0GA1UEERMG
+MTItMzQ1MQ0wCwYDVQQKEwRPTkFQMQ0wCwYDVQQLEwRvbmFwMRwwGgYDVQQDExNj
+ZXJ0aXNzdWVyLm9uYXAub3JnMQ4wDAYDVQQFEwUxMjM0NTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAPdrWRYpdGY6A9YEQ8mnQdOW7wzdaNHJ83ZrMPZd
+V7jBOMvQbTw6Oe/Q4vD+Dla7FmGqlAajNIgKRiUUQLKVmASELhCYhtW7Mn91qe6l
+xuyPyOEi9o8mArJosFAfPPF0nm9FQPi2qHgyi6C52QR7cKsgNPflpKVsEx9Y+Zns
+YBqkaX16BukvcHUANgsvZ3rLUVeiOsCi2ysVcsm+4XMvF6ejoqKJ9k7Ti0VrQtqh
+e1nKlaa4uP3dreeUXBMLfKUS7QrNavpiX6wVaohVp6p/AYQ2HZurMv86Q2E5D5SC
+ReEpVuWx+r4MI8dAHbYe09ntkRGIe8mVyxHHEWLNfZiwKGsCAwEAAaCBlzCBlAYJ
+KoZIhvcNAQkOMYGGMIGDMFUGA1UdEQROMEyCCWxvY2FsaG9zdIITY2VydGlzc3Vl
+ci5vbmFwLm9yZ4ENb25hcEBvbmFwLm9yZ4cEfwAAAYYVb25hcDovL2NsdXN0ZXIu
+bG9jYWwvMAsGA1UdDwQEAwICBDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
+AwIwDQYJKoZIhvcNAQELBQADggEBAHDMw3+fVOrbVnMI2g/IP40vt1eenkoriTHX
+dnjRRFio75nCNRJdLOJ9FU3wIgdDZwGaiXdn5NDQxCe0BWcbElDJSYR/xOi7V0AM
+2L3CrRAOhr2MjwX7CaOuYWcVtrbtIMf26NLKRXYPlGgc6YeofalDnezMJ/IuRQhj
+bcm17a8owa5dH9u/rmTmlrIT7PV4JHkZIogctIcSqod6xdr1mbi8G9DMFAqV+o7W
+9kV7XDKhTqYoBIsXwfehNMu3lo72VuklIyVNiEVz4mVzpeZy2DgjRjCLt106yDHZ
+f3nco6O4y2EyexBVKq6QRFfZDUab6YcoEVvPAio01RmFrHgnxHs=
+-----END CERTIFICATE REQUEST-----`)
diff --git a/certServiceK8sExternalProvider/src/x509/x509_utils.go b/certServiceK8sExternalProvider/src/x509/x509_utils.go
new file mode 100644 (file)
index 0000000..b8b03e1
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * ============LICENSE_START=======================================================
+ * oom-certservice-k8s-external-provider
+ * ================================================================================
+ * Copyright (C) 2020 Nokia. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package x509
+
+import (
+       "bytes"
+       "crypto/x509"
+       "encoding/pem"
+       "fmt"
+)
+
+// decodeCSR decodes a certificate request in PEM format and returns the
+func DecodeCSR(data []byte) (*x509.CertificateRequest, error) {
+       block, rest := pem.Decode(data)
+       if block == nil || len(rest) > 0 {
+               return nil, fmt.Errorf("unexpected CSR PEM on sign request")
+       }
+       if block.Type != "CERTIFICATE REQUEST" {
+               return nil, fmt.Errorf("PEM is not a certificate request")
+       }
+       csr, err := x509.ParseCertificateRequest(block.Bytes)
+       if err != nil {
+               return nil, fmt.Errorf("error parsing certificate request: %v", err)
+       }
+       if err := csr.CheckSignature(); err != nil {
+               return nil, fmt.Errorf("error checking certificate request signature: %v", err)
+       }
+       return csr, nil
+}
+
+// encodeX509 will encode a *x509.Certificate into PEM format.
+func EncodeX509(cert *x509.Certificate) ([]byte, error) {
+       caPem := bytes.NewBuffer([]byte{})
+       err := pem.Encode(caPem, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
+       if err != nil {
+               return nil, err
+       }
+       return caPem.Bytes(), nil
+}
diff --git a/certServiceK8sExternalProvider/src/x509/x509_utils_test.go b/certServiceK8sExternalProvider/src/x509/x509_utils_test.go
new file mode 100644 (file)
index 0000000..2692bf4
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * ============LICENSE_START=======================================================
+ * oom-certservice-k8s-external-provider
+ * ================================================================================
+ * Copyright (C) 2020 Nokia. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package x509
+
+import (
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+
+       "onap.org/oom-certservice/k8s-external-provider/src/x509/testdata"
+)
+
+func TestShouldDecodeCSR(t *testing.T) {
+       csr, err := DecodeCSR([]byte(testdata.ValidCertificateSignRequest))
+
+       assert.Nil(t, err)
+       assert.Equal(t, "ONAP", csr.Subject.Organization[0])
+}
+
+func TestShouldReturnError(t *testing.T) {
+       _, err := DecodeCSR([]byte(testdata.InvalidCertificateSignRequest))
+
+       assert.NotNil(t, err)
+}