@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License .
* /
// Package legacydb is emulates the behavior of the old signer client by polling from a MySQL database using the old
// Package legacydb emulates the behavior of the old signer client by polling from a MySQL database using the old
// schema, reading CSR files from the filesystem and storing certificates in the file system.
package legacydb
@ -26,6 +26,7 @@ import (
"crypto/rand"
"crypto/x509"
"database/sql"
"encoding/pem"
"errors"
"fmt"
"math/big"
@ -172,6 +173,14 @@ SET warning = warning + 1
WHERE id = ? `
)
const (
prefixOpenPGP = "gpg"
prefixPersonalClient = "client"
prefixPersonalServer = "server"
prefixOrganizationalClient = "orgclient"
prefixOrganizationalServer = "orgserver"
)
type pendingResponse struct {
responseType responseType
rowID int
@ -315,6 +324,12 @@ func New(logger *logrus.Logger, config *config.Database, commands chan *protocol
respOrganizationalServerCertificate : "org_server" ,
}
supportedHashAlgorithms := map [ string ] crypto . Hash {
"sha256" : crypto . SHA256 ,
"sha384" : crypto . SHA384 ,
"sha512" : crypto . SHA512 ,
}
failureQuery := map [ responseType ] string {
respGPG : sqlRecordFailedOpenPGP ,
respPersonalClientCertificate : sqlRecordFailedPersonalClientCertificate ,
@ -332,6 +347,7 @@ func New(logger *logrus.Logger, config *config.Database, commands chan *protocol
logger : logger ,
commands : commands ,
emails : emails ,
algorithms : supportedHashAlgorithms ,
issuerIDs : issuerIDs ,
profiles : profiles ,
pending : pending ,
@ -540,7 +556,7 @@ func (d *LegacyDB) requestCerts(ctx context.Context, query string, rt responseTy
var (
csrID int
csrFileName string
certType int
certType sql . NullInt16
md string
subject string
)
@ -549,7 +565,7 @@ func (d *LegacyDB) requestCerts(ctx context.Context, query string, rt responseTy
return fmt . Errorf ( "could not scan row: %w" , err )
}
csr Bytes, err := os . ReadFile ( csrFileName )
pem Bytes, err := os . ReadFile ( csrFileName )
if err != nil {
d . logger . WithFields ( logrus . Fields {
"id" : csrID ,
@ -561,6 +577,23 @@ func (d *LegacyDB) requestCerts(ctx context.Context, query string, rt responseTy
continue
}
csrBlock , remaining := pem . Decode ( pemBytes )
if len ( remaining ) > 0 {
d . logger . WithFields ( logrus . Fields { "id" : csrID , "file_name" : csrFileName } ) . Warn ( "unhandled CSR bytes" )
idsWithIssues = append ( idsWithIssues , csrID )
continue
}
if csrBlock . Type != "CERTIFICATE REQUEST" {
d . logger . WithFields ( logrus . Fields { "id" : csrID , "file_name" : csrFileName , "pem_block_type" : csrBlock . Type } ) . Warn ( "unhandled PEM block type" )
idsWithIssues = append ( idsWithIssues , csrID )
continue
}
hashAlg , ok := d . algorithms [ md ]
if ! ok {
d . logger . WithFields ( logrus . Fields { } ) . Warn ( "unsupported hash algorithm" )
@ -582,22 +615,11 @@ func (d *LegacyDB) requestCerts(ctx context.Context, query string, rt responseTy
continue
}
signCertCommand := buildSignCertificateCommand ( issuerID , profileID , csrBlock . Bytes , subjParts , hashAlg )
command := & protocol . Command {
Announce : messages . BuildCommandAnnounce ( messages . CmdSignCertificate ) ,
Command : messages . SignCertificateCommand {
IssuerID : issuerID ,
ProfileName : profileID ,
CSRData : csrBytes ,
CommonName : subjParts . Subject . CommonName ,
Organization : subjParts . Subject . Organization [ 0 ] ,
OrganizationalUnit : subjParts . Subject . OrganizationalUnit [ 0 ] ,
Locality : subjParts . Subject . Locality [ 0 ] ,
Province : subjParts . Subject . Province [ 0 ] ,
Country : subjParts . Subject . Country [ 0 ] ,
Hostnames : subjParts . DNSNames ,
EmailAddresses : subjParts . EmailAddresses ,
PreferredHash : hashAlg ,
} ,
Command : signCertCommand ,
}
d . Lock ( )
@ -617,6 +639,45 @@ func (d *LegacyDB) requestCerts(ctx context.Context, query string, rt responseTy
return nil
}
func buildSignCertificateCommand (
issuerID string ,
profileID string ,
csrBytes [ ] byte ,
subjParts * x509 . Certificate ,
hashAlg crypto . Hash ,
) messages . SignCertificateCommand {
signCertCommand := messages . SignCertificateCommand {
IssuerID : issuerID ,
ProfileName : profileID ,
CSRData : csrBytes ,
CommonName : subjParts . Subject . CommonName ,
Hostnames : subjParts . DNSNames ,
EmailAddresses : subjParts . EmailAddresses ,
PreferredHash : hashAlg ,
}
if len ( subjParts . Subject . Organization ) > 0 {
signCertCommand . Organization = subjParts . Subject . Organization [ 0 ]
}
if len ( subjParts . Subject . OrganizationalUnit ) > 0 {
signCertCommand . OrganizationalUnit = subjParts . Subject . OrganizationalUnit [ 0 ]
}
if len ( subjParts . Subject . Locality ) > 0 {
signCertCommand . Locality = subjParts . Subject . Locality [ 0 ]
}
if len ( subjParts . Subject . Province ) > 0 {
signCertCommand . Province = subjParts . Subject . Province [ 0 ]
}
if len ( subjParts . Subject . Country ) > 0 {
signCertCommand . Country = subjParts . Subject . Country [ 0 ]
}
return signCertCommand
}
var (
errInvalidSANPart = errors . New ( "invalid SAN part, missing colon" )
errUnsupportedSubjectPart = errors . New ( "unsupported subject part" )
@ -702,19 +763,23 @@ func parseSubjectStringComponent(identifier, value string, res *x509.Certificate
}
func ( d * LegacyDB ) revokePersonalClientCerts ( _ context . Context ) error {
panic ( "not implemented" )
logrus . Debug ( "not implemented" )
return nil
}
func ( d * LegacyDB ) revokePersonalServerCerts ( _ context . Context ) error {
panic ( "not implemented" )
logrus . Debug ( "not implemented" )
return nil
}
func ( d * LegacyDB ) revokeOrganizationClientCerts ( _ context . Context ) error {
panic ( "not implemented" )
logrus . Debug ( "not implemented" )
return nil
}
func ( d * LegacyDB ) revokeOrganizationServerCerts ( _ context . Context ) error {
panic ( "not implemented" )
logrus . Debug ( "not implemented" )
return nil
}
func ( d * LegacyDB ) writeCertificate ( prefix string , rowID int , signatureData [ ] byte ) ( string , error ) {
@ -728,10 +793,10 @@ func (d *LegacyDB) writeCertificate(prefix string, rowID int, signatureData []by
return crtFileName , nil
}
func ( d * LegacyDB ) recordCertificate ( _ context . Context , query string , rowID int , certBytes [ ] byte ) error {
func ( d * LegacyDB ) recordCertificate ( _ context . Context , prefix, query string , rowID int , certBytes [ ] byte ) error {
panic ( fmt . Sprintf (
"not implemented: record certificate with query %s for rowID %d (%d bytes)",
query, rowID , len ( certBytes ) ,
"not implemented: record certificate to prefix %s with query %s for rowID %d (%d bytes)",
prefix, query, rowID , len ( certBytes ) ,
) )
}
@ -778,7 +843,7 @@ func (d *LegacyDB) recordSignedOpenPGPKey(ctx context.Context, rowID int, signat
gpgExpiry := entity . Subkeys [ 0 ] . Sig . CreationTime . Add ( time . Second * time . Duration ( * lifeTimeSecs ) )
crtFileName , err := d . writeCertificate ( "gpg" , rowID , signatureData )
crtFileName , err := d . writeCertificate ( prefixOpenPGP , rowID , signatureData )
if err != nil {
return fmt . Errorf ( "could not write OpenPGP result: %w" , err )
}
@ -847,13 +912,13 @@ func (d *LegacyDB) handleSignedCertificate(
switch pending . responseType {
case respPersonalClientCertificate , respPersonalCodeSigningCertificate :
err = d . recordCertificate ( ctx , sqlRecordPersonalClientCert, pending . rowID , r . CertificateData )
err = d . recordCertificate ( ctx , prefixPersonalClient, sqlRecordPersonalClientCert, pending . rowID , r . CertificateData )
case respPersonalServerCertificate :
err = d . recordCertificate ( ctx , sqlRecordPersonalServerCert, pending . rowID , r . CertificateData )
err = d . recordCertificate ( ctx , prefixPersonalServer, sqlRecordPersonalServerCert, pending . rowID , r . CertificateData )
case respOrganizationalClientCertificate , respOrganizationalCodeSigningCertificate :
err = d . recordCertificate ( ctx , sqlRecordOrganizationalClientCert, pending . rowID , r . CertificateData )
err = d . recordCertificate ( ctx , prefixOrganizationalClient, sqlRecordOrganizationalClientCert, pending . rowID , r . CertificateData )
case respOrganizationalServerCertificate :
err = d . recordCertificate ( ctx , sqlRecordOrganizationalServerCert, pending . rowID , r . CertificateData )
err = d . recordCertificate ( ctx , prefixOrganizationalServer, sqlRecordOrganizationalServerCert, pending . rowID , r . CertificateData )
default :
return fmt . Errorf ( "unexpected response type for pending request %s" , announce . ID )
}
@ -936,7 +1001,8 @@ func (d *LegacyDB) sendNotificationEmail(ctx context.Context, e emailData) error
return fmt . Errorf ( "could not set text template for email body: %w" , err )
}
c , err := mail . NewClient ( "localhost" )
const smtpPort = 1025
c , err := mail . NewClient ( "localhost" , mail . WithPort ( smtpPort ) )
if err != nil {
return fmt . Errorf ( "could not create mail client: %w" , err )
}