// Copyright 1995-2016 The OpenSSL Project Authors. 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
//
//     https://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.

#include <assert.h>
#include <stdio.h>

#include <openssl/asn1.h>
#include <openssl/bn.h>
#include <openssl/buffer.h>
#include <openssl/err.h>
#include <openssl/objects.h>
#include <openssl/x509.h>

#include "internal.h"


using namespace bssl;

int X509_REQ_print_fp(FILE *fp, const X509_REQ *x) {
  BIO *bio = BIO_new_fp(fp, BIO_NOCLOSE);
  if (bio == nullptr) {
    OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB);
    return 0;
  }
  int ret = X509_REQ_print(bio, x);
  BIO_free(bio);
  return ret;
}

int X509_REQ_print_ex(BIO *bio, const X509_REQ *x, unsigned long nmflags,
                      unsigned long cflag) {
  long l;
  STACK_OF(X509_ATTRIBUTE) *sk;
  char mlch = ' ';

  int nmindent = 0;

  if ((nmflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) {
    mlch = '\n';
    nmindent = 12;
  }

  if (nmflags == X509_FLAG_COMPAT) {
    nmindent = 16;
  }

  const X509_REQ_INFO *ri = x->req_info;
  if (!(cflag & X509_FLAG_NO_HEADER)) {
    if (BIO_write(bio, "Certificate Request:\n", 21) <= 0 ||
        BIO_write(bio, "    Data:\n", 10) <= 0) {
      goto err;
    }
  }
  if (!(cflag & X509_FLAG_NO_VERSION)) {
    l = X509_REQ_get_version(x);
    // Only zero, `X509_REQ_VERSION_1`, is valid but our parser accepts some
    // invalid values for compatibility.
    assert(0 <= l && l <= 2);
    if (BIO_printf(bio, "%8sVersion: %ld (0x%lx)\n", "", l + 1,
                   (unsigned long)l) <= 0) {
      goto err;
    }
  }
  if (!(cflag & X509_FLAG_NO_SUBJECT)) {
    if (BIO_printf(bio, "        Subject:%c", mlch) <= 0 ||
        X509_NAME_print_ex(bio, ri->subject, nmindent, nmflags) < 0 ||
        BIO_write(bio, "\n", 1) <= 0) {
      goto err;
    }
  }
  if (!(cflag & X509_FLAG_NO_PUBKEY)) {
    if (BIO_write(bio, "        Subject Public Key Info:\n", 33) <= 0 ||
        BIO_printf(bio, "%12sPublic Key Algorithm: ", "") <= 0 ||
        i2a_ASN1_OBJECT(bio, FromOpaque(ri->pubkey)->algor->algorithm) <= 0 ||
        BIO_puts(bio, "\n") <= 0) {
      goto err;
    }

    const EVP_PKEY *pkey = X509_REQ_get0_pubkey(x);
    if (pkey == nullptr) {
      BIO_printf(bio, "%12sUnable to load Public Key\n", "");
      ERR_print_errors(bio);
    } else {
      EVP_PKEY_print_public(bio, pkey, 16, nullptr);
    }
  }

  if (!(cflag & X509_FLAG_NO_ATTRIBUTES)) {
    if (BIO_printf(bio, "%8sAttributes:\n", "") <= 0) {
      goto err;
    }

    sk = x->req_info->attributes;
    if (sk_X509_ATTRIBUTE_num(sk) == 0) {
      if (BIO_printf(bio, "%12sa0:00\n", "") <= 0) {
        goto err;
      }
    } else {
      for (size_t i = 0; i < sk_X509_ATTRIBUTE_num(sk); i++) {
        // TODO(crbug.com/442860745): `X509_ATTRIBUTE` accessors are not
        // const-correct.
        X509_ATTRIBUTE *a = sk_X509_ATTRIBUTE_value(sk, i);
        const ASN1_OBJECT *aobj = X509_ATTRIBUTE_get0_object(a);

        if (X509_REQ_extension_nid(OBJ_obj2nid(aobj))) {
          continue;
        }

        if (BIO_printf(bio, "%12s", "") <= 0) {
          goto err;
        }

        const int num_attrs = X509_ATTRIBUTE_count(a);
        const int obj_str_len = i2a_ASN1_OBJECT(bio, aobj);
        if (obj_str_len <= 0) {
          if (BIO_puts(bio, "(Unable to print attribute ID.)\n") < 0) {
            goto err;
          } else {
            continue;
          }
        }

        for (int j = 0; j < num_attrs; j++) {
          for (int k = 25 - obj_str_len; k > 0; k--) {
            if (BIO_write(bio, " ", 1) != 1) {
              goto err;
            }
          }

          if (BIO_puts(bio, ":") <= 0) {
            goto err;
          }

          const ASN1_TYPE *at = X509_ATTRIBUTE_get0_type(a, j);
          if (at->type == V_ASN1_PRINTABLESTRING ||
              at->type == V_ASN1_UTF8STRING || at->type == V_ASN1_IA5STRING ||
              at->type == V_ASN1_T61STRING) {
            const ASN1_STRING *str = at->value.asn1_string;
            int str_len = ASN1_STRING_length(str);
            if (BIO_write(bio, ASN1_STRING_get0_data(str), str_len) !=
                str_len) {
              goto err;
            }
            BIO_puts(bio, "\n");
          } else {
            BIO_puts(bio, "unable to print attribute\n");
          }
        }
      }
    }
  }

  if (!(cflag & X509_FLAG_NO_EXTENSIONS)) {
    STACK_OF(X509_EXTENSION) *exts = X509_REQ_get_extensions(x);
    if (exts) {
      BIO_printf(bio, "%8sRequested Extensions:\n", "");

      for (size_t i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
        const X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, i);
        if (BIO_printf(bio, "%12s", "") <= 0) {
          goto err;
        }
        const ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex);
        i2a_ASN1_OBJECT(bio, obj);
        const int is_critical = X509_EXTENSION_get_critical(ex);
        if (BIO_printf(bio, ": %s\n", is_critical ? "critical" : "") <= 0) {
          goto err;
        }
        if (!X509V3_EXT_print(bio, ex, cflag, 16)) {
          BIO_printf(bio, "%16s", "");
          ASN1_STRING_print(bio, X509_EXTENSION_get_data(ex));
        }
        if (BIO_write(bio, "\n", 1) <= 0) {
          goto err;
        }
      }
      sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
    }
  }

  if (!(cflag & X509_FLAG_NO_SIGDUMP) &&
      !X509_signature_print(bio, x->sig_alg, x->signature)) {
    goto err;
  }

  return 1;

err:
  OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB);
  return 0;
}

int X509_REQ_print(BIO *bio, const X509_REQ *req) {
  return X509_REQ_print_ex(bio, req, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
}
