MDM证书制作

简介

MDM中分为Vendor 和Customer两个角色,即服务商和用户。

如果你有个企业开发者账号,没错就是$299的那个,你既可以是Vendor,也可以是Customer。作为一个Vendor,你可以为Customer的证书请求文件颁发个用于签名的证书。</pre>

如果你仅仅是个Customer也就是没有$299的账号,只能等Vendor给你颁发个.cer证书、签名产生个plist_encoded 文件,然后提交到https://identity.apple.com/pushcert/,如果文件不正确会提示格式错误,若正确会生成一个用于推送的证书mdm.pem。</pre>

以下操作默认你的账号已经被授权了MDM服务功能,下面将以Vendor的角色进行以下操作。

1、生成MDM证书

作为一个vendor,首先要生成用户签名的.cer证书,具体步骤如下:

  • 打开钥匙串,菜单栏选择钥匙串访问->证书助理->从证书颁发机构请求证书,然后随便填一个电子邮件,选择存储到磁盘,命名成mdm_vendor.certSigningRequest

  • 登录开发者中心到Certificates,选择创建证书,拉到底下Services,然后选择MDM CSR.下一步的choose File选择上一步生成的mdm_vendor.certSigningRequest文件。创建完成后下载。再到钥匙串里找到MDM Vender开头的刚才那个证书,然后导出p12文件。这里会要求输入一个密码,后面会用到。这里把密码设置成1,因为这边的p12包含了过期信息,后面要传到监控平台,监控平台的解密码设置成1了

  • 接下来把mdm_vendor.p12转化成mdm_vendor.key格式openssl pkcs12 -in mdm_vendor.p12 -nocerts -nodes -legacy -out mdm_vendor.key

    这里参考教程里使用的是openssl pkcs12 -in mdm_vendor.p12 -nocerts -out mdm_vendor.key,但是会报错,因为新版本的openssl移除了一些算法(我用的是3.4.1版本的ssl),需要在命令里显示的调用已经被移除的算法

作为一个customer

  • 在终端中生成customer.csr
openssl genrsa -des3 -out customerPrivateKey.pem 2048
再执行:
    openssl req -new -key customerPrivateKey.pem -out customer.csr
    执行这一步需要输入各种公司信息,可以参考一下信息
    Enter pass phrase for root.key: ← 输入前面创建的密码 
    You are about to be asked to enter information that will be incorporated 
    into your certificate request. 
    What you are about to enter is what is called a Distinguished Name or a DN. 
    There are quite a few fields but you can leave some blank 
    For some fields there will be a default value, 
    If you enter ‘.’, the field will be left blank. 
    —– 
    Country Name (2 letter code) [AU]:HK ← 国家代号,美国输入US 
    State or Province Name (full name) [Some-State]:Hong Kong ← 省的全名,拼音 
    Locality Name (eg, city) []:Hong Kong ← 市的全名,拼音 
    Organization Name (eg, company) [Internet Widgits Pty Ltd]: hp ← 公司英文名 
    Organizational Unit Name (eg, section) []: ← 可以不输入 我输入的公司名称
    Common Name (eg, YOUR name) []: ← 此时不输入,和后面的需要输入ip或者域名不一样,这里不能输入,输入了好像证书有问题 
    Email Address []:xxx@xx.com ← 电子邮箱,可随意填
    
    Please enter the following ‘extra’ attributes 
    to be sent with your certificate request 
    A challenge password []: ← 可以不输入 
    An optional company name []: ← 可以不输入</pre>

customer.csr签名

下载

  • AppleWWDRCA.cer下载 脚本里原来的AppleWWDRCA已经过期了,下载最新的G6会导致后面上传苹果会显示失败,实测这里使用G3是可以正常使用的。下载完成后,把文件名改成AppleWWDRCA.cer,方便后面直接使用命令行

  • AppleIncRootCertificate下载

  • 由于mac命令行现在只支持python3,需要安装python2,并且由于 Python 2 已经停止支持,Homebrew 已经移除了 python@2 的官方支持。需要冲从 Python 官网下载 macOS 安装包: https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg

  • 生成plist_encoded:这里需要把文章末尾的python代码保存成mdm_vendor_sign.py到同目录下,然后终端cd到目录然后执行python2 mdm_vendor_sign.py --key mdm_vendor.key --csr customer.csr --mdm mdm.cer --root AppleIncRootCertificate.cer --WWDR AppleWWDRCA.cer

    这里遇到了一些问题:

    • 1:路径出现中文可能会导致失败

    • 2:原脚本里验证customer.crs的代码,可能由于openssl升级导致这边验证有问题,所以这里对原脚本做了修正处理。

    • 3:如果后面生成的plist_encoded有问题,可以使用命令base64 -D -i plist_encoded -o decoded.plist把文件转成明文的plist文件查看里面的各种信息是否有问题

  • https://identity.apple.com/pushcert/提交生成的plist_encoded。如果文件有问题会提示无效的文件,如果一切正常会生成我们最后需要的MDM_Certificate.pem的证书

对MDM_Certificate.pem证书进行格式化转换

在终端中输入openssl pkcs12 -export -in MDM_Certificate.pem -out MDM_Certificate.p12 -inkey customerPrivateKey.pem即可得到MDM_Certificate.p12文件,后续把这个文件丢给服务端就可以了

python脚本

# http://www.softhinker.com/in-the-news/iosmdmvendorcsrsigning
# fuck java
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import argparse
from plistlib import writePlistToString
import os
import subprocess
from base64 import b64encode
import sys
import urllib2

def p(s):
 sys.stdout.write(s)
 sys.stdout.flush()

def mdm_vendor_sign():
 """
 This utility will create a properly encoded certifiate signing request
 that you can upload to identity.apple.com/pushcert
 """

 parser = argparse.ArgumentParser(description=mdm_vendor_sign.__doc__)
 parser.add_argument('--key', help='Private key', required=True)
 parser.add_argument('--csr', help='Certificate signing request', required=True)
 parser.add_argument('--mdm', help='MDM vendor certificate', required=True)

 parser.add_argument('--root', help='AppleIncRootCertificate', required=True)
 parser.add_argument('--WWDR', help='AppleWWDRCA', required=True)

 parser.add_argument('--out', help='Output filename', required=False)

 #.....

 cli_args = vars(parser.parse_args())

 # Verify CSR
 # openssl req -text -noout -verify -in CSR.csr
 p('Verifying %s ... ' % cli_args['csr'])

 print("aaa", cli_args['csr'])
 print("bbb", os.path.abspath(cli_args['csr']))
 print("ccc", os.path.exists(cli_args['csr']))

 csr_file = open(cli_args['csr']).read()
 args = ['openssl', 'req', '-noout', '-verify', '-quiet']
 command = subprocess.Popen(args, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
 output, error = command.communicate(input = csr_file) 
 print(repr(output))
 print("OpenSSL", output)
 print("OpenSSL", error)

 if output.rstrip().split('\n')[0] == 'Certificate request self-signature verify OK':
 p('OK\n')
 else:
 p('FAILED1\n')
 return


 # Verify private key
 # openssl rsa -in privateKey.key -check
 p('Verifying %s ... ' % cli_args['key'])
 key_file = open(cli_args['key']).read()
 args = ['openssl', 'rsa', '-check', '-noout' ]
 command = subprocess.Popen(args, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
 output, error = command.communicate(input = key_file) 
 if output.rstrip().split('\n')[0] == 'RSA key ok':
 p('OK\n')
 else:
 p('FAILED2\n\n')
 print """If you don't have the plain private key already, you need
to extract it from the pkcs12 file...

First convert to PEM
openssl pkcs12 -in filename.p12 -nocerts -out key.pem

Then export the certificate file from the pfx file
openssl pkcs12 -in filename.pfx -clcerts -nokeys -out cert.pem

Lastly Remove the passphrase from the private key
openssl rsa -in key.pem -out the_private_key.key
"""
 return


 # Verify MDM vendor certificate
 # openssl x509 -noout -in mdm.cer -inform DER
 p('Verifying %s ... ' % cli_args['mdm'])
 mdm_cert_file = open(cli_args['mdm'],'rb').read()  # Binary read
 args = ['openssl', 'x509', '-noout', '-inform', 'DER' ]
 command = subprocess.Popen(args, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
 output, error = command.communicate(input = mdm_cert_file) 
 if len(output) == 0:
 p('OK\n')
 else:
 p('FAILED\n')
 return


 # Convert CSR to DER format
 # openssl req -inform pem -outform der -in customer.csr -out customer.der
 p('Converting %s to DER format... ' % cli_args['csr'])
 args = ['openssl', 'req', '-inform', 'pem', '-outform', 'der' ]
 command = subprocess.Popen(args, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
 output, error = command.communicate(input = csr_file) 
 if error:
 p('FAILED\n')
 return
 p('OK\n')
 csr_der = output
 csr_b64 = b64encode(csr_der)


 # Sign the CSR with the private key 
 # openssl sha1 -sign private_key.key -out signed_output.rsa data_to_sign.txt
 p('Signing CSR with private key... ')
 args = ['openssl', 'sha1', '-sign', cli_args['key'] ]
 command = subprocess.Popen(args, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
 output, error = command.communicate(input = csr_der)
 if error:
 p('FAILED\n')
 return
 p('OK\n')
 signature_bytes = output
 signature = b64encode(signature_bytes)


 def cer_to_pem(cer_data):
 # openssl x509 -inform der -in mdm.cer -out mdm.pem
 # -in and -out flags are handled by STDIN and STDOUT
 args = ['openssl', 'x509', '-inform', 'der' ]
 command = subprocess.Popen(args, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
 output, error = command.communicate(input = cer_data)
 if error:
 p('Error converting from cer to pem: %s' % error)
 return output


 # TODO : Probably should verify these too

 p('Downloading WWDR intermediate certificate...')
 # intermediate_cer = urllib2.urlopen('https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer').read()
 # p(' converting to pem...')
 # intermediate_pem = cer_to_pem(intermediate_cer)
 # p('OK\n')

 # p('Downloading Apple Root Certificate...')
 # root_cer = urllib2.urlopen('http://www.apple.com/appleca/AppleIncRootCertificate.cer').read()
 # p(' converting to pem...')
 # root_pem = cer_to_pem(root_cer)
 # p('OK\n')

 #.....
 root_cert_file = open(cli_args['root'],'rb').read()
 wwdr_cert_file = open(cli_args['WWDR'],'rb').read()
 intermediate_pem = cer_to_pem(wwdr_cert_file)
 root_pem = cer_to_pem(root_cert_file)


 mdm_pem = cer_to_pem(mdm_cert_file)

 print("\n=== MDM Vendor Certificate (PEM) ===")
 print(mdm_pem)

 print("\n=== Intermediate (WWDR) Certificate (PEM) ===")
 print(intermediate_pem)

 print("\n=== Root (Apple) Certificate (PEM) ===")
 print(root_pem)


 p('Finishing...')
 plist_dict = dict(
 PushCertRequestCSR = csr_b64,
 PushCertCertificateChain = mdm_pem + intermediate_pem + root_pem,
 PushCertSignature = signature
 )
 plist_xml = writePlistToString(plist_dict)
 plist_b64 = b64encode(plist_xml)

 output_filename =  cli_args['out'] if  cli_args['out'] else 'plist_encoded'
 write_path = os.path.join(os.getcwd(), output_filename)
 output = open(write_path, 'wb')
 output.write(plist_b64)
 output.close()
 p('DONE\n\nGo upload file \'%s\' to identity.apple.com/pushcert !\n' % output_filename)



if __name__=="__main__":
 mdm_vendor_sign()</pre>

参考_

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容