// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

// Generates root_darwin_arm64.go.
//
// As of iOS 8, there is no API for querying the system trusted X.509 root
// certificates. We could use SecTrustEvaluate to verify that a trust chain
// exists for a certificate, but the x509 API requires returning the entire
// chain.
//
// Apple publishes the list of trusted root certificates for iOS on
// support.apple.com. So we parse the list and extract the certificates from
// an OS X machine and embed them into the x509 package.
package main

import (
	"bytes"
	"compress/gzip"
	"crypto/x509"
	"encoding/pem"
	"flag"
	"fmt"
	"go/format"
	"io/ioutil"
	"log"
)

var output = flag.String("output", "root_darwin_arm64.go", "file name to write")

func main() {
	certs, err := selectCerts()
	if err != nil {
		log.Fatal(err)
	}

	buf := new(bytes.Buffer)

	fmt.Fprintf(buf, "// Code generated by root_darwin_arm_gen --output %s; DO NOT EDIT.\n", *output)
	fmt.Fprintf(buf, "%s", header)
	for _, cert := range certs {
		gzbuf := new(bytes.Buffer)
		zw, err := gzip.NewWriterLevel(gzbuf, gzip.BestCompression)
		if err != nil {
			log.Fatal(err)
		}
		if _, err := zw.Write(cert.Raw); err != nil {
			log.Fatal(err)
		}
		if err := zw.Close(); err != nil {
			log.Fatal(err)
		}
		fmt.Fprintf(buf, "p.addCertFuncNotDup(%q, %q, certUncompressor(%q))\n",
			cert.RawSubject,
			cert.SubjectKeyId,
			gzbuf.Bytes())
	}
	fmt.Fprintf(buf, "%s", footer)

	source, err := format.Source(buf.Bytes())
	if err != nil {
		log.Fatal("source format error:", err)
	}
	if err := ioutil.WriteFile(*output, source, 0644); err != nil {
		log.Fatal(err)
	}
}

func selectCerts() (certs []*x509.Certificate, err error) {
	pemCerts, err := ioutil.ReadFile("certs.pem")
	if err != nil {
		return nil, err
	}
	for len(pemCerts) > 0 {
		var block *pem.Block
		block, pemCerts = pem.Decode(pemCerts)
		if block == nil {
			break
		}
		if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
			continue
		}

		cert, err := x509.ParseCertificate(block.Bytes)
		if err != nil {
			return nil, err
		}
		certs = append(certs, cert)
	}
	return certs, nil
}

const header = `
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package x509

func loadSystemRoots() (*CertPool, error) {
	p := NewCertPool()
`

const footer = `
	return p, nil
}
`