前言
关于MDM,谷歌搜遍了也搜不出多少资料,甚至有的资料会误导小伙伴们。我实现了MDM并且整理了一份详细的文档,供大家参考,表述有误之处请见谅并及时在评论里告知我修改。
转载请注明出处:http://www.jianshu.com/p/2173e0df5761
参考链接:
http://www.jianshu.com/p/fef831dfe12c
http://blog.csdn.net/column/details/ios-mdm.html
http://blog.csdn.net/kmyhy/article/details/23171017
http://www.mbaike.net/mdm/24.html
参考文档:(链接我就不放了,大家自己找吧,找不到也没关系)
InsideAppleMDM.pdf
CommandReference.pdf
正文
以下“服务器”都是指MDM服务器,而且必须是https服务器
MDM服务器与APNS、设备的大致通信流程
1、生成并配置好mobileconfig文件,放在服务器上
2、设备访问服务器上的mobileconfig文件,点击注册以及信任按钮后,设备主动发起请求mobileconfig里的checkin URL。设备首先发起Authenticate,服务端录入数据后返回空plist,接着设备发起TokenUpdate,服务端录入数据后返回空plist。
3、以锁屏为例,服务端将锁屏命令发给APNS,当苹果的 APNS 服务器通知设备访问 MDM 服务器时,设备首先会向服务器(mobileconfig里的server URL)发送一个Status:Idle 消息(如果设备空闲),表示 MDM 服务器现在可以把指令取给它执行。服务器组装成 Plist 文件响应给它。
4、设备执行完命令,会再次向 server 发送 Acknowledged 消息,告诉服务器执行状态,然后服务器简单回复一个空响应(即200),并关闭连接。
以下是MDM vendor和customer申请制作
MDM Vendor申请(必须是企业版开发者账号)
1、前往https://developer.apple.com/contact/submit.php给苹果留言,说明你要申请MDM以及申请理由。
2、若干天后,苹果会回复一封邮件,让你打电话给他们,并且给你提供了一个case number。打电话时必须要报开发者证书代理人姓名,以及case number,才会给你开放。
3、客服会帮你开通,成功后她会发给你一封邮件,带有MDM的详细介绍链接,然后在developer center里,创建生产证书那边会新增一个MDM CSR选项,表示申请成功。
MDM 证书制作和申请
(建议在Mac电脑下操作,如果是Windows则要先安装openssl和python,(Mac自带了它们),而且命令可能有区别,建议所有文件都统一放到一个文件夹下!所有命令都在该文件夹下操作!以下步骤需要输入密码,请务必记住密码,建议统一所有密码!)
创建MDM Vendor CSR,并上传到developer center创建MDM证书
1、钥匙串->钥匙串访问->证书助理->从证书颁发机构请求证书->填写开发者账号的Apple ID(例如:myCompany@qq.com)、常用名称(公司名称+MDM,例如:MyCompany MDM)、选择存储到磁盘,生成CertificateSigningRequest.certSigningRequest,保存.
2、前往developer center,创建证书->MDM CSR,上传刚才创建的CertificateSigningRequest.certSigningRequest,生成mdm.cer,下载下来,双击安装到钥匙串(登录->证书)。
创建MDM推送CSR
再次打开钥匙串->钥匙串访问->证书助理->从证书颁发机构请求证书->填写开发者账号的Apple ID(例如:myCompany@qq.com)、常用名称(公司名称+MDMPush,例如:MyCompany MDMPush)、选择存储到磁盘,生成mdm_push.certSigningRequest,保存.
导出私钥并制作证书
1、点击展开mdm.cer安装到钥匙串的证书,导出私钥为private.p12,保存。
2、将私钥private.p12提取出私钥
openssl pkcs12 -in private.p12 -nocerts -out key.pem
3、提取证书
openssl pkcs12 -in private.p12 -clcerts -nokeys -out cert.pem
4、将证书转换成DES格式
openssl x509 -in cert.pem -inform PEM -out mdm.cer -outform DES
5、去掉private key密码
openssl rsa -in key.pem -out private.key
使用mdm_vendor_sign工具制作CSR
1、下载mdm_vendor_sign(https://github.com/grinich/mdmvendorsign)
2、运行python mdm_vendor_sign.py --key private.key --csr mdm_push.certSigningRequest --mdm mdm.cer --out applepush.csr
3、运行成功后,会提示 Go upload file 'applepush.csr' to identity.apple.com/pushcert !,否则为不成功。
4、如果不成功,则需要做一些改动:
首先手动下载AppleWWDRCA.cer证书到此目录 ([https://developer.apple.com/certificationauthority/AppleWWDRCA.cer](https://developer.apple.com/certificationauthority/AppleWWDRCA.cer))
修改mdm_vendor_sign.py 代码128行为:intermediate_cer = open(‘AppleWWDRCA.cer','r').read()
再次运行即可。
从Apple获取推送证书
1、将上一步生成的applepush.csr上传到[https://identity.apple.com/pushcert](https://identity.apple.com/pushcert)
2、下载推送证书,安装到钥匙串,显示 APSP:xxxxxx
3、导出该推送证书为p12,给服务端使用。
MDM Customer
(Vendor生成后的证书是通用的,而接下来的customer则是和服务器地址有关,所以更换服务器地址时则要重新完成以下步骤)
生成配置mobileconfig文件
1、下载IPCU(iPhone Configuration Utility,网上搜一下就有下载地址,如果下载下来的发现无法完成以下步骤,说明你下错了,再去找找)(网上说苹果已废弃它,实际上废弃的仅仅只是它的主要功能而已,它仍然能够用于配置生成mobileconfig文件)。
2、打开IPCU,选择配置描述文件->新建,即新建一个配置描述文件
3、点击通用,填写名称、标识符(该描述文件的唯一标识,例如:com.公司名.mdm)、机构、描述、安全性
4、点击凭证-> + ,添加服务器的ca根证书,再点击+,添加用服务器证书和key生成的p12文件,填写密码。(如果不清楚https服务器证书如何生成,请参考底下的“https生成自签名证书”)
5、点击移动设备管理,填写服务器URL(server)、登记URL(checkin),打开钥匙串,找到vendor步骤里安装的推送证书(APSP:xxxxxx),双击,复制用户id,粘贴到主题。 身份选择在凭证里添加的p12,“移除时检查”勾选上时,在移除描述文件时会向MDM服务器发起checkout请求,建议勾选,其他的选项根据需求去勾选,最后一项使用开发APNS服务器不要勾选!
6、导出->安全性选择“无”,导出为mobileconfig文件。
7、将mobileconfig放在服务器上,提供下载接口,设备用safari访问该接口,即可自动打开设置进入描述文件的安装界面,点击注册->注册->信任,如果安装成功,到此步骤即完成了证书的申请配置以及描述文件的配置安装,接下来就是MDM服务器的搭建和调试与设备的通信了。
8、设备与服务端的请求都是PUT请求,具体可通过抓包查看,服务端的代码可参考https://github.com/zuoyy/IOS-MDM-Server
实现了功能还不够,仍然有几个问题需要解决:
1、客户端如何检查是否已安装了描述文件?(即是否可控?):
解决方案:目前我能想到的办法是通过判断当前服务器的https证书是否已受信任来解决,因为描述文件携带的凭证含有服务器的https证书,如果判断的结果为已信任,则说明已安装了该描述文件,可接受控制;否则就是没有安装了。
判断的代码如下:
<pre>
<code>
+ (BOOL)IsCertificatesTrusted:(NSArray<NSData *> *)certDatas {
if (certDatas.count == 0) {
return NO;
}
CFMutableArrayRef certs = CFArrayCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeArrayCallBacks);
for (NSData *certData in certDatas) {
SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) certData);
if (!cert) {
continue;
}
CFArrayAppendValue(certs, cert);
CFRelease(cert);
}
SecPolicyRef policy = SecPolicyCreateBasicX509();
SecTrustRef trust;
OSStatus err = SecTrustCreateWithCertificates(certs, policy, &trust);
CFRelease(certs);
CFRelease(policy);
if (!trust) {
return NO;
}
if (err != errSecSuccess) {
CFRelease(trust);
return NO;
}
SecTrustResultType trustResult = -1;
err = SecTrustEvaluate(trust, &trustResult);
CFRelease(trust);
if (err != errSecSuccess) {
return NO;
}
if(trustResult == kSecTrustResultUnspecified) {
return YES;
} else {
return NO;
}
}
</code>
</pre>
2、断网情况下移除描述文件,服务器如何更新数据库?
如果你在配置mobileconfig时有勾选上“移除时检查”,那么在联网情况下如果移除描述文件,设备会主动发起checkout请求告诉服务器设备已退出控制,服务器可更新数据库。
但是断网的情况下怎么办?
虽然第一个问题解决了客户端判断设备是否已安装了描述文件,但是设备在checkin提交的设备唯一标识是UDID,而IOS是不允许用代码获取设备的UDID的,也就是说,客户端无法告诉服务器设备当前到底可不可控。
在谷歌上搜索到了这么一篇文章:http://www.mbaike.net/mdm/24.html
从中想到的方案是:
服务端可通过定期主动发起查询命令来判断当前设备是否可控。
该方案理论上可行,但不知是否会引发其他问题,待验证。如果有大神有完美的解决方案,请带我。
https生成自签名证书
一、创建CA证书
1、创建一个私钥,命名为rootCA.key
openssl genrsa -out rootCA.key 2048
2、创建根证书,命名为rootCA.cer,(common name填写服务器地址)
openssl req -x509 -new -key rootCA.key -out rootCA.cer -days 730
######二、制作自签名 SSL 证书
1、创建一个私钥,命名为server.key
openssl genrsa -out server.key 2048
2、创建CSR
openssl req -new -out server.req -key server.key -subj /CN=127.0.0.1/CN=填写服务器地址/CN=localhost
3、用CSR创建SSL证书
openssl x509 -req -in server.req -out server.cer -CAkey rootCA.key -CA rootCA.cer -days 36500 -CAcreateserial -CAserial server.serial
4、将 .key 和 .cer 文件导出为 .p12 证书
openssl pkcs12 -export -in server.cer -inkey server.key -out server.p12 -name "server"
5、将 .p12 文件导入到 Java keystore 中
keytool -importkeystore -v -srckeystore server.p12 -srcstoretype pkcs12 -srcstorepass 密码 -destkeystore server.keystore -deststoretype jks -deststorepass 密码